说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正。若在阅读时有任何的问题,也可通过评论提出,本人将根据自身能力对问题进行一定的解答。

手撸Spring系列是笔者本人首次尝试的、较为规范的系列博客,将会围绕Spring框架分为 IOC/DI 思想Spring MVCAOP 思想Spring JDBC 四个模块,并且每个模块都会分为 理论篇源码篇实战篇 三个篇章进行讲解(大约12篇文章左右的篇幅)。从原理出发,深入浅出,一步步接触Spring源码并手把手带领大家一起写一个 迷你版的Spring框架,促进大家进一步了解Spring的本质!

由于源码篇涉及到源码的阅读,可能有小伙伴没有成功构建好Spring源码的阅读环境,笔者强烈建议:想要真正了解Spring,一定要构建好源码的阅读环境再进行研究,具体构建过程可查看笔者此前的博客:《如何构建Spring5源码阅读环境》

文章目录

  • 前言
  • 一、IOC架构
    • 1.BeanFactory
    • 2.BeanDefinition
    • 3.BeanDefinitionReader
  • 二、从IOC的入口开始
    • 1.实例化ApplicationContext
    • 2.查看AnnotationConfigApplicationContext的构造方法
      • 2.1调用空构造方法
        • 2.1.1 AnnotatedBeanDefinitionReader
          • 1. ConfigurationClassPostProcessor
          • 2. AutowiredAnnotationBeanPostProcessor
          • 3. RequiredAnnotationBeanPostProcessor
          • 4. CommonAnnotationBeanPostProcessor
          • 5. PersistenceAnnotationBeanPostProcessor
          • 6. EventListenerMethodProcessor
          • 7. DefaultEventListenerFactory
        • 2.1.2 ClassPathBeanDefinitionScanner
      • 2.2 注册bean配置类
      • 2.3 刷新上下文
        • 1. prepareRefresh
        • 2. obtainFreshBeanFactory
          • 实现一
          • 实现二
        • 3. prepareBeanFactory
        • 4. postProcessBeanFactory
        • 5. invokeBeanFactoryPostProcessors
        • 6. registerBeanPostProcessors
        • 7. initMessageSource
        • 8. initApplicationEventMulticaster
        • 9. onRefresh
        • 10. registerListeners
        • 11. finishBeanFactoryInitialization
        • 12. finishRefresh
        • 13. destroyBeans
        • 14. cancelRefresh
        • 15. resetCommonCaches
  • 总结

前言

今天的博客将带领大家一起来目睹一番Spring5的源码,透过源码去发掘Spring是如何具体去实现IOC思想的。由于Spring IOC DI 两个源码讲解写一起篇幅会比较长,因此笔者将IOC和DI分成了两篇博客进行讲解。

在开篇: 手撸Spring系列0:系统架构介绍(开篇)中我们有介绍到,模块 spring-beansspring-core 主要实现Spring IOC 和 DI功能,那么接下来我们将从这两个模块开始去解读Spring的源码。


一、IOC架构

1.BeanFactory

在Spring中,提供了许多IOC容器实现的方式由用户自己自由选择(下图是Spring IOC 架构图)

BeanFactory是Spring中的顶层接口,定义了IOC容器的基本功能规范,而在BeanFactory之下存在三个重要的子类,分别是:ListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactory,并且这三个子类接口最终都由默认实现类 DefaultListableBeanFactory 实现。

可能会有读者伙伴们开始疑惑了,为什么一个用于生产Bean的工厂底下还有有这么多个子类?虽然他们继承自一个”父亲“,但他们的老”父亲“为了能更好的完成家族工作,扩大业务宽度,需要他们各自负责一块领域,并通过不同的职责给他们起了对应的名字。

  • ListableBeanFactory:正如这个工厂接口的名字所示(能列在表单上的bean工厂),这个工厂接口最大的特点就是可以列出工厂可以生产的所有实例。

  • HierarchicalBeanFactory:分层级的bean工厂,该接口与他的大哥ListableBeanFactory不同的是:大哥将所有的bean实例统一的列在一张表中,但这样做的问题在于,工作出现问题后的追责问题会使得管理员十分头痛。而此时二弟HierarchicalBeanFactory职责的优势就显现出来了,他会将每个bean所属的”公司“、”部门“等都进行一个归类,此时,工作出现问题后,管理员能够快速的找到出现问题的”部门“,并进行追责。

  • AutowireCapableBeanFactory:定义bean自动装配规则

顶层接口BeanFactory源码:

package org.springframework.beans.factory;import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;public interface BeanFactory {/*** <p>*     这里是对FactoryBean的转义定义,因为如果使用bean的名字检索*     FactoryBean得到的对象是工厂生成的对象*     如果需要得到工厂本身,需要转义* </p>*/String FACTORY_BEAN_PREFIX = "&";/*** <p>*     这里根据bean的名字,在IOC容器中得到bean实例,*     这个IOC容器就是一个大的抽象工厂。* </p>*/Object getBean(String name) throws BeansException;/*** <p>*     这里根据bean的名字和Class类型来得到bean实例,*     和上面的方法不同在于它会抛出异常:*     如果根据名字取得的bean实例的Class类型和需要的不同的话。* </p>*/<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;Object getBean(String name, Object... args) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType, Object... argsa) throws BeansException;/*** <p>这里提供对bean的检索,看看是否在IOC容器有这个名字的bean</p>*/boolean containsBean(String name);/*** <p>这里根据bean名字得到bean实例,并同时判断这个bean是不是单例</p>*/boolean isSingleton(String name) throws NoSuchBeanDefinitionException;/*** <p>这里根据bean名字得到bean实例,并同时判断这个bean是不是原型</p>*/boolean isPrototype(String name) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;/*** <p>这里对得到bean实例的Class类型</p>*/@NullableClass<?> getType(String name) throws NoSuchBeanDefinitionException;/*** <p>这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来</p>*/String[] getAliases(String name);}

从源码中,我们不难看出,BeanFactory只是对IOC容器进行了基本行为的定义,并不关心一个bean是如何产生定义的。这就如同我们在手机实体店中挑选手机,只关心手机最后呈现出来的性能、外观等因素,而我们不用去关注手机厂商具体是如何生产这部手机的。


2.BeanDefinition

什么是BeanDefinition: 如果将一个bean比喻成一个婴儿,那么BeanDefinition则是这个婴儿体内的DNA。DNA中存储着这个婴儿各种生命基因,双眼皮、单眼皮、黄皮肤、黑皮肤等等都由基因决定,甚至获取到该婴儿的DNA后还可以克隆到一模一样的个体。而BeanDefinition就相当于是bean的DNA,其中定义了与bean实例化相关的各种信息,并通过BeanDefinition中的信息就可以实例化出一个bean对象。(如下是BeanDefinition的类结构图)


3.BeanDefinitionReader

在系列博客的开篇:手撸Spring系列0:系统架构介绍(开篇)中,笔者曾和各位读者伙伴们讲述过,ApplicationContext作为BeanFactory的子类,他们之间的区别是:前者扫描bean后会对bean进行实例化,而后者则是等到bean被调用时才进行实例化。

但一个bean的解析过程是十分复杂的,功能会被划分的非常详细,因为需要保证其扩展性、延申性和灵活性,以应对项目的各种变化。而bean的解析过程则是通过BeanDefinitionReader来完成的。(如下是BeanDefinitionReader的类结构图)


二、从IOC的入口开始

大概的了解Spring IOC 的基本架构后,我们就要正式的开始来阅读源码了,但源码这么多,上千个类,我们应从何读起?了解了基本架构后,就如同观察了一个建筑的大致外貌,要更深入的研究就必须进去建筑内部查看,这时我们就需要找到建筑的入口,但入口又是在哪呢?

不妨先来回想一下,当我们启动一个以spring为框架的程序时,程序首先会去找到Java入口方法main方法,对spring的IOC容器ApplicationContext进行实例化,然后进行spring内部的一系列操作后才开始处理和执行业务需求……等等,我们似乎已经找到突破口了,spring需要在IOC容器ApplicationContext进行实例化后才开始开始真正的工作,也就是说,ApplicationContext其实是spring框架的入口,那么我们可以尝试从ApplicationContext开始,去一步步探索spring源码,以揭开它神秘的面纱!

1.实例化ApplicationContext

因为ApplicationContext本身是一个接口,因此我们需要实例化其子类AnnotationConfigApplicationContext(这里我们使用注解配置的子类AnnotationConfigApplicationContext,除此之外还有以xml文件为配置的ClassPathXmlApplicationContext)

public static void main(String[] args) {ApplicationContext applicationContext =new AnnotationConfigApplicationContext(AppConfig.class);}

2.查看AnnotationConfigApplicationContext的构造方法

进入AnnotationConfigApplicationContext的非空构造方法(如下)

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {// 初始化注解解析器reader,扫描器scannerthis();// 注册配置类annotatedClassesregister(annotatedClasses);// 扫描bean的具体操作refresh();}

进入构造方法后,我们可以看到,里面执行了三个方法thisregisterrefresh,他们对应的作用分别是:

  • this: 调用AnnotationConfigApplicationContext的空构造方法
  • register: 注册bean配置类
  • refresh: 刷新上下文

2.1调用空构造方法

在阅读这个空构造方法的源码之前,笔者需要向各位读者朋友们温故一个Java的基础知识点:Java中要求在子类的构造方法中调用其父类的构造方法。如果父类无构造方法(其实是一个默认无参的构造方法),那么子类的构造方法中会自动进行调用;如果 父类有自己的构造方法(这时父类不会有默认无参的构造方法),那么在子类的构造方法中,必须要调用父类的某个构造方法,而且必须是在构造方法的第一个语句中进行调用。

因此,在真正执行this();方法之前,Java会先执行父类中的构造方法,即AnnotationConfigApplicationContext的父类 GenericApplicationContext 中的构造方法。(GenericApplicationContext的空构造方法源码如下)

public GenericApplicationContext() {this.beanFactory = new DefaultListableBeanFactory();}

在这里我们发现,GenericApplicationContext 在初始化时居然实例化了一个 DefaultListableBeanFactory,也就是我们的bean工厂。作为BeanFactory的实现类,我们不妨点进去查看查看他的源码。其中,值得注意的是,在众多的成员变量中存在一个名为 beanDefinitionMap 的map(如下)

/*** <p>bean定义对象的map,按bean名称为键值</p>*/
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

在前面的段落中,笔者使用了婴儿和基因的关系类比bean和BeanDefinition的关系,那么beanDefinitionMap对应的又是什么呢?他就好比是存储基因的基因库,存储着各色各样的基因,以用作bean的实例化。

此时相信很多的读者朋友们思路已经很开朗了。父类GenericApplicationContext的构造方法作用是用于实例化出一个bean工厂,也因此我们就拥有了基因库beanDefinitionMap,那么子类AnnotationConfigApplicationContext接下来的任务无疑就是往基因库中添加基因BeanDefinition。那么Spring官方又是怎么实现的呢?我们把目光重新回到AnnotationConfigApplicationContext的空构造方法中(如下)

public AnnotationConfigApplicationContext() {// 在IOC容器中初始化一个 注解bean读取器this.reader = new AnnotatedBeanDefinitionReader(this);// 在IOC容器中初始化一个 按类路径扫描注解bean的 扫描器this.scanner = new ClassPathBeanDefinitionScanner(this);}
2.1.1 AnnotatedBeanDefinitionReader

首先我们先来查看AnnotatedBeanDefinitionReader的构造方法源码:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {this(registry, getOrCreateEnvironment(registry));}public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");Assert.notNull(environment, "Environment must not be null");this.registry = registry;this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}

构造方法中除了成员变量的赋值外,在最后一行调用了工具类AnnotationConfigUtils中的registerAnnotationConfigProcessors方法,通过该方法的名称我们就可以大概知道该方法的用途(寄存器注释配置处理器
),接下来我们就继续查看egisterAnnotationConfigProcessors的源码,探究一下构造AnnotatedBeanDefinitionReader时发生了什么:

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {registerAnnotationConfigProcessors(registry, null);}public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);if (beanFactory != null) {if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());}}Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4);if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}return beanDefs;}

可以看到,在该方法中主要任务是完成spring内部7个默认bean的注册

  1. ConfigurationClassPostProcessor
  2. AutowiredAnnotationBeanPostProcessor
  3. RequiredAnnotationBeanPostProcessor
  4. CommonAnnotationBeanPostProcessor
  5. PersistenceAnnotationBeanPostProcessor
  6. EventListenerMethodProcessor
  7. DefaultEventListenerFactory

1. ConfigurationClassPostProcessor

工厂后置处理器,类上的注解基本都在此解析,spring的包扫描也在里面完成。由于我们目标是为了自己实现一个迷你版的spring,对于该该处理器更细致的阅读,笔者将会在以后的博客中在详细解读。我们暂且知道各个处理器负责功能即可!

if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}

2. AutowiredAnnotationBeanPostProcessor

用于处理 @Autowired 的后置处理器,如mybatis中的mapper属性注入就是通过该处理器进行处理注入的!

if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}

3. RequiredAnnotationBeanPostProcessor

用于处理 @Required 注解的后置处理器

if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}

4. CommonAnnotationBeanPostProcessor

处理公共注解的后置处理器,如:@PostConstruct@PreDestroy@Resource等。

if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}

5. PersistenceAnnotationBeanPostProcessor

提供的用于处理注解@PersistenceUnit和@PersistenceContext的处理器。用于注入相应的JPA资源:EntityManagerFactory和EntityManager (或者它们的子类变量)。

if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}

6. EventListenerMethodProcessor

对注解 @EventListener 的处理器,实现spring的事件监听

if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}

7. DefaultEventListenerFactory

EventListenerMethodProcessor中会调用DefaultEventListenerFactory的方法,注册的具体实现是由DefaultEventListenerFactory处理

if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}

看到这里,相信各位读者已经知道了实例化AnnotatedBeanDefinitionReader的主要作用其实是注册spring内部的7个处理器。


2.1.2 ClassPathBeanDefinitionScanner

在搞懂了AnnotatedBeanDefinitionReader的大致作用后,我们回到AnnotationConfigApplicationContext的构造方法来,继续进入另一条实例化语句的类中ClassPathBeanDefinitionScanner

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {this(registry, true);}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {this(registry, useDefaultFilters, getOrCreateEnvironment(registry));}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,Environment environment) {this(registry, useDefaultFilters, environment,(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,Environment environment, @Nullable ResourceLoader resourceLoader) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");this.registry = registry;if (useDefaultFilters) {registerDefaultFilters();}setEnvironment(environment);setResourceLoader(resourceLoader);}

在这其中值得关注的是registerDefaultFilters方法,点击进入该方法:

protected void registerDefaultFilters() {this.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.}try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}}

看到这个方法的第一行,这一行代码任务的其实是扫描特殊的类,比如注解类 @Component (包括我们熟知的 @Controll@Service@Repository 等)

至此,this()方法的任务完成的有:

  1. 初始化bean工厂
  2. 注册处理器
  3. 扫描特殊的类(如注解类)

小结:相信有spring基础的读者朋友们可以很快的理解官方这么设计的原因,但刚接触的读者伙伴们可能还是有点懵。不妨我们比喻一下:BeanFactroy就是一家工厂,而this中调用父类方法实例化BeanFactory其实就是在建立工厂的建筑,接下来实例化AnnotatedBeanDefinitionReader中几个默认处理器,这些处理器我们可以看做成是一台台需要处理工作的机器,日后会帮助我们完成工厂的具体生产工作;而实例化ClassPathBeanDefinitionScanner则是制定给我们的工厂入口原料制定了指标,不是所有的原料都可以进入到工厂中制作成为产品的,如:劣质的原料等,只有“达标”的原理才可以进入生产线。(希望这样的比喻可以让大家更好的理解)


2.2 注册bean配置类

回到AnnotationConfigApplicationContext的构造方法中:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {// 初始化注解解析器reader,扫描器scannerthis();// 注册配置类annotatedClassesregister(annotatedClasses);// 扫描bean的具体操作refresh();}

在上面的段落中,this方法已经完成了他自己的”使命“,接下来我们继续研究接下来的方法register(annotatedClasses)

public void register(Class<?>... annotatedClasses) {Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");this.reader.register(annotatedClasses);}

进入到register方法的源码,发现其调用了在this方法中赋值的readerAnnotatedBeanDefinitionReader对象中的register方法,我们继续进入,查看其源码:

public void register(Class<?>... annotatedClasses) {for (Class<?> annotatedClass : annotatedClasses) {registerBean(annotatedClass);}}public void registerBean(Class<?> annotatedClass) {doRegisterBean(annotatedClass, null, null, null);}<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}abd.setInstanceSupplier(instanceSupplier);ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {for (Class<? extends Annotation> qualifier : qualifiers) {if (Primary.class == qualifier) {abd.setPrimary(true);}else if (Lazy.class == qualifier) {abd.setLazyInit(true);}else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}for (BeanDefinitionCustomizer customizer : definitionCustomizers) {customizer.customize(abd);}BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}

此方法主要是按照用户需求将特定的规则配置好,如:是否需要懒加载

小结:在this方法中,我们的工厂虽然已经拥有了多台机器(处理器),但每个机器都是一些比较多功能的,并不是一台只能完成一个工作的机器,他们有着许多模式,可以联合生产出许多不同的产品。这时,如果我们需要机器们生产出一个符合用户要求的产品,我们就需要按照用户的需求对每台机器进行一定的设置,最终生产出符合用户需求的产品。而这就是register方法所完成的任务


2.3 刷新上下文

通过上两个方法的小结,相信读者朋友们都可以猜到最后一个方法需要完成的任务了。是的,经过前两个方法任务的完成后,我们拥有了工厂建筑、原理指标、以及调试好的产品生产机器接下来就是运送原料进入工厂,并制造产品的具体过程啦!。进入refresh()方法中查看源码:

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 1.设置容器的启动日期和活动标志以及执行属性源的任何初始化prepareRefresh();// 2.获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 3.设置beanFactory的属性prepareBeanFactory(beanFactory);try {// 4.允许在上下文子类中对bean工厂进行后处理postProcessBeanFactory(beanFactory);// 5.调用在上下文中注册为bean的工厂处理程序invokeBeanFactoryPostProcessors(beanFactory);// 6.注册拦截bean创建的bean处理器registerBeanPostProcessors(beanFactory);// 7.初始化此上下文的消息源initMessageSource();// 8.初始化此上下文的事件多播程序initApplicationEventMulticaster();// 9.初始化特定上下文子类中的其他特殊beanonRefresh();// 10.检查侦听器bean并注册它们registerListeners();// 11.实例化所有剩余的(非惰性init)单例对象finishBeanFactoryInitialization(beanFactory);// 12.最后一步:发布相应的事件finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// 13.销毁已经创建的单例destroyBeans();// 14.重置同步标识cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// 15.重设公共缓存resetCommonCaches();}}}

源码中可以看出,refresh方法主要调用了15个方法(分别对应15步操作)。


1. prepareRefresh

设置容器的启动日期和活动标志以及执行属性源的任何初始化

protected void prepareRefresh() {// 设置容器启动时间this.startupDate = System.currentTimeMillis();// 设置closed、active状态值this.closed.set(false);this.active.set(true);if (logger.isInfoEnabled()) {logger.info("Refreshing " + this);}// 初始化上下文环境中的任何占位符属性源initPropertySources();// 验证所有标记为required的属性都是可解析的getEnvironment().validateRequiredProperties();// Allow for the collection of early ApplicationEvents,// to be published once the multicaster is available...this.earlyApplicationEvents = new LinkedHashSet<>();}

小结:由于这家工厂的上一任负责人管理不当,工厂倒闭了,你决定接管这个工厂,于是你需要去相关部门办理相关证件,并且证件中记录了你的办理时间(也就是源码中的startupDate),关闭的工厂得以重新开启(closed=false; active=true


2. obtainFreshBeanFactory

obtainFreshBeanFactory这里主要的作用其实是运送原料进入工厂,beanDefinition的注册是在这里完成的。其实现方式有两种,第一种是需要判断是否存在bean工厂,若存在则销毁并创建新的工厂,并为新工厂加上锁;第二种则是只给工厂加上锁。

实现一

org.springframework.context.support.AbstractRefreshableApplicationContext.class

protected final void refreshBeanFactory() throws BeansException {// 若存在工厂,则将其销毁if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 创建新的工厂DefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);// 加载beanDefinitionloadBeanDefinitions(beanFactory);// 加上锁synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}
实现二

org.springframework.context.support.GenericApplicationContext.class

protected final void refreshBeanFactory() throws IllegalStateException {if (!this.refreshed.compareAndSet(false, true)) {throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");}// 加锁this.beanFactory.setSerializationId(getId());}

小结:证件搞下来了,你进入工厂查看情况,发现工厂中有着许多上一任负责人留下的机器原料等物品。如果你打算工厂按照旧生产线生产原来的产品,你大可留下这些物品接着制造产品。但如果你准备生产别的产品,那么旧机器对你来说就没有什么用处了,你可将其销毁掉,重新购买一些新的机器原料


3. prepareBeanFactory

配置标准的beanFactory,设置ClassLoader,设置SpEL表达式解析器,添加忽略注入的接口,添加bean,添加bean后置处理器等。其实通过命名我们可以知道,该方法需要完成的任务是在bean工厂创建完成后到工厂真正运作前的准备工作(比如:将制作产品的机器-处理器摆放到正确的位置,以便机器准备启动进入工作状态等)


4. postProcessBeanFactory

模板方法,此时,所有的beanDefinition已经加载,但是还没有实例化。
允许在子类中对beanFactory进行扩展处理。比如添加ware相关接口自动装配设置,添加后置处理器等,是子类扩展prepareBeanFactory(beanFactory)的方法。除了基础的机器设施外,工厂可能还会为用户定制一些特殊的产品,而这时就需要其他的机器设备的介入帮忙。方法prepareBeanFactory就是帮助我们完成购买这些机器的任务!


5. invokeBeanFactoryPostProcessors

IOC容器的初始化过程有着三个重要的步骤:

  1. 资源定位
  2. beanDefinition的载入
  3. 将beanDefinition以键值对应的方式存入map中

以上三个步骤都在该方法下完成 !!!
invokeBeanFactoryPostProcessors源码:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}

顺着invokeBeanFactoryPostProcessors,我们继续进入第一行中invokeBeanFactoryPostProcessors的源码:(该方法下将会获取所有的BeanDefinitionRegistryPostProcessor实现类,首先过滤出实现 PriorityOrdered(优先级)接口的BeanDefinitionRegistryPostProcessor,对其进行排序后调用方法;接着过滤实现Ordered(顺序)接口的BeanDefinitionRegistryPostProcessor,进行排序后调用方法,调用所有 其他BeanFactoryPostProcessors

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.Set<String> processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);}else {regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();}

在这其中,我们发现有多处代码都在调用方法invokeBeanFactoryPostProcessors,此方法具体实现十分复杂,如果读者朋友们不嫌麻烦的话可以尝试使用idea打个断点,一直debug到org.springframework.context.annotation.ComponentScanAnnotationParser的方法 parse 时,查看属性basePackages

获取到了我们在配置类的注解中 @ComponentScan(“com.bosen.www”) 的包名,此时完成了第一步操作 定位资源,那我们不妨进入parse方法中调用的doscan方法:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();for (String basePackage : basePackages) {Set<BeanDefinition> candidates = findCandidateComponents(basePackage);// 开始扫描bean,并解析为beanDefinitionfor (BeanDefinition candidate : candidates) {ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 将beanDefinition存入beanDefinitionMap中registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}

至此,IOC容器初始化过程中的三大步骤已经全部完成!!


6. registerBeanPostProcessors

进入registerBeanPostProcessors方法如下:

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);}

接着进入PostProcessorRegistrationDelegate.registerBeanPostProcessors

public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);// Register BeanPostProcessorChecker that logs an info message when// a bean is created during BeanPostProcessor instantiation, i.e. when// a bean is not eligible for getting processed by all BeanPostProcessors.int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));// Separate between BeanPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, register the BeanPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);// Next, register the BeanPostProcessors that implement Ordered.List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();for (String ppName : orderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}sortPostProcessors(orderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, orderedPostProcessors);// Now, register all regular BeanPostProcessors.List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String ppName : nonOrderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);// Finally, re-register all internal BeanPostProcessors.sortPostProcessors(internalPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, internalPostProcessors);// Re-register post-processor for detecting inner beans as ApplicationListeners,// moving it to the end of the processor chain (for picking up proxies etc).beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));}

小结:其实这一步操作也很好理解,与上一步类似,在完成原本工作的过程中,可能会出现另外一些情况。比如:原本的产品都是生产完成后直接放在商场等实体商店中直接销售的。但是有的用户会在网上下单,这时我们就需要对产品进行快递打包,在产品原本的包装上,还需要加上避免快递运输碰撞的保护包装,而这一步的工作就是交给registerBeanPostProcessors去完成的。


7. initMessageSource

做国际化功能;消息绑定,消息解析;针对于国际化问题的MessageSource


8. initApplicationEventMulticaster

初始化事件派发器(广播器)


9. onRefresh

spring5中并未对该方法进行实现,是一个空的方法。因此,在子类中可以对其执行自定义的逻辑操作。


10. registerListeners

注册监听器


11. finishBeanFactoryInitialization

实例化所有剩余的(非惰性init)单例对象


12. finishRefresh

最后一步:发布相应的事件

protected void finishRefresh() {// 清除上下文级资源缓存(例如扫描ASM元数据)。clearResourceCaches();// 1. 初始化此上下文的生命周期处理器。initLifecycleProcessor();// 2. 首先将刷新传播到生命周期处理器。getLifecycleProcessor().onRefresh();// 3.推送上下文刷新完毕事件到相应的监听器publishEvent(new ContextRefreshedEvent(this));// Participate in LiveBeansView MBean, if active.LiveBeansView.registerApplicationContext(this);}

到此,IOC容器已经可以宣告初始化成功了!!!


13. destroyBeans

销毁已经创建的单例(工厂出现异常,内部的对象全部销毁)

protected void destroyBeans() {getBeanFactory().destroySingletons();}

14. cancelRefresh

重置同步标识(工厂出现异常,关闭工厂,并将活跃状态改为false

protected void cancelRefresh(BeansException ex) {this.active.set(false);}

15. resetCommonCaches

重设公共缓存

protected void resetCommonCaches() {ReflectionUtils.clearCache();ResolvableType.clearCache();CachedIntrospectionResults.clearClassLoader(getClassLoader());}

总结

工厂的创建,到开始生产产品的过程中,我们发现,该工厂的负责人有是一位非常有“远见”的人,思考问题也非常的细致。一个Bean工厂,本能的任务其实就只是生产出bean就可以了,但是负责人客户想的非常周全,在完成基本任务的前提下,还为客户提供了以后可能会出现的各种需求的解决方案(如:AOPDI等),真就应了那句“顾客就是上帝”啊!

手撸Spring系列2:IOC/DI 思想(源码篇-IOC)相关推荐

  1. 手撸Spring系列12:MyBatis(源码篇)

    说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...

  2. 手撸Spring系列13:MyBatis(实战篇)

    说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...

  3. 手撸Spring系列4:IOC/DI 思想(实战篇)

    说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...

  4. 手撸Spring系列10:Spring AOP(实战篇)

    说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...

  5. 手撸Spring系列8:Spring AOP(理论篇)

    说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...

  6. spring系列-注解驱动原理及源码-自动装配

    目录 一.spring规范的bean自动注入 1.使用@Autowired自动注入 2.使用@Qualifier指定需要装配的组件 3.使用@Autowired装配null对象 4.使用@Primar ...

  7. spring系列-注解驱动原理及源码-AOP使用及源码解析

    目录 一.用注解方式开启AOP 1.实例 2.AOP简单小结 二.AOP原理 1.@EnableAspectJAutoProxy溯源 2.AnnotationAwareAspectJAutoProxy ...

  8. spring系列-注解驱动原理及源码-声明式事务使用及原理解析

    目录 一.环境准备 1.JdbcTemplate使用实例 2.事务添加 二.声明式事务源码分析 1.原理(与AOP非常相似) 一.环境准备 1.JdbcTemplate使用实例 (1)pom文件添加依 ...

  9. spring系列-注解驱动原理及源码-bean生命周期

    目录 一.Bean的初始化和销毁 1.@Bean指定初始化和销毁方法 2.通过实现InitializingBean和Disposabean来初始化和销毁bean 3.使用JSR250定义的@PostC ...

最新文章

  1. 威斯康辛大学《机器学习导论》2020秋季课程完结,课件、视频资源已开放(附下载)...
  2. bash: ifconfig: command not found
  3. Windows下使用idea git 插件
  4. go标准库的学习-fmt
  5. 模拟spring - 简单实现spring IOC
  6. SQLAlchemy 几种查询方式总结
  7. mysql tinyint和char(1)性能对比
  8. mysql中的count函数和sum函数如果条件不符合返回什么
  9. QT的QOpenGLTextureBlitter类的使用
  10. 教小学妹学算法:十大经典排序算法深度解析
  11. AWS EC2实例Ubuntu系统设置root用户密码并使用root/ubuntu用户登录
  12. java.lang.ClassNotFoundException: org.apache.jsp.WEB_002dINF.classes.views.index_jsp
  13. 苹果6s最大屏幕尺寸_iPhone 6s:经典的小屏旗舰,百元价位也能做苹果党
  14. Android PdfViewer
  15. 【★★★★★】提高PHP代码质量的36个技巧
  16. SCCM2012系列之六,SCCM2012部署前的WDS准备
  17. nginx + lua 构建网站防护waf(一)
  18. 【转载】COMSOL Multiphysics 5.3a 安装教程
  19. 冒险教主-超详细绘制教程
  20. 基于XTerm模拟发包实现

热门文章

  1. QT之CheckBox单项选择与多项选择
  2. 如何查看一个Visual Studio项目是用哪个VS版本开发的
  3. 消息称Snapchat将收购自制表情应用开发商Bitstrips
  4. APP性能测试_帧率测试
  5. 全球与中国航空资产管理市场深度研究分析报告
  6. wu版-天下无难试之Redis面试题刁难大全
  7. JS中解决单击双击事件的冲突的问题
  8. JS实现多线程--Concurrent.Thread.js
  9. 从原理到策略算法再到架构产品看推荐系统 | 附Spark实践案例
  10. Android笔记:浅析Android电视APP开发