spring-ioc源码

需要解决的问题
  1. beanfactory和factorybean的区别
  2. beanfactorypostprocessor在spring中的作用
  3. springioc的加载过程
  4. bean的生命周期
  5. spring中有哪些扩展接口及调用时机

大纲

1. 主要流程-springioc的加载过程
  1. 实例化容器AnnotationConfigApplicationContext
  2. 实例化工厂DefaultListAbleBeanFactory
  3. 实例化建立beanDefination读取器 annotatedBeandefinationReader
  4. 创建beandefination扫描器:classPathBeanDefiantionScanner
  5. 注册配置类为beanDefination: register方法,annotatedClasses
  6. refresh
  7. invokeBeanfacorypostProcessors(beanfactory)
  8. finishBeanfactoryinitialization(beanfactory)
2. 主要流程-spring bean的生命周期

springioc的加载过程

  1. 首先准备个例子如下(插入图片)
  2. 2.springioc的容器加载流程
  3. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);

    annotationConfigApplicationContext的关系图如下

    创建annotationConfigApplicationContext对象

    首先看这个构造方法

  4. ​ 3.4 如果没有配置类会字节返回

    ​ 3.5 处理排序

    ​ 3.6 解析配置类,可能是full类,也可能是lite类

    ​ 3.7 在第六步的时候只是注册了部分Bean,但是如@Import@Bean,是没有被注册的。

    因为可以有多个配置类,所以需要循环处理。我们的配置类的BeanDefinition是AnnotatedBeanDefinition的实例,所以会进入第一个

    if

    重点在于doProcessConfigurationClass方法,需要特别注意,最后一段代码,会把configClass放于一个map,

  1. 这是一个有参构造方法,可以接受多个配置类,不过一般情况只传入一个配置类。

  2. 这个配置类有俩种情况,一种是传统意义上的带@Configutarion注解的配置类,还有一种是带@Component,@import,@importResource等注解的配置类,在spring中前者被称为full配置类,后者叫lite配置类,也叫普通bean

    查看这个this()方法都干了什么,如图

    spring-ioc源码_spring

    spring-ioc源码_spring_02

    首先无参构造方法中就是对读取器read和扫描器进行了实例化,reader的类型是annotatedbeandefinitionReader,可以看出他是一个 bean定义读取器,scanner的类型是classpathbeandefinitionscanner,它仅仅是外面手动调用.scan方法,

  3. 实例化工厂:defaultListableBeanFactory

    spring-ioc源码_实例化_03

    DefaultListableBeanFactory的关系图

    spring-ioc源码_实例化_04

    defaultlistablebeanfactory是bean的工厂,是用来生产和获得bean。

  4. 实例化建beanDefinition读取器:annotatedbeandefinitionReader

    主要负责俩件事

    1. 注册内置beanPostprocrssor

      1. 注册相关的beandefinition

    spring-ioc源码_实例化_05

    ​ 回到annotationconfigapplicationcontext的无参构造方法,看annotatedbeandefinitionreader

    spring-ioc源码_构造方法_06

    这里beandefinitionregistry是annotationconfigapplicationcontext的实例,这里调用其他类构造方法

    spring-ioc源码_晋升高级-spring_07

    spring-ioc源码_spring_08

    spring-ioc源码_实例化_09

    这个方法就是注册spring的内置的多个bean

    1. 判断容器内是否存在configurationclasspostprocessor bean

      1. 如果不存在,就通过rootBeanDefinition的构造方法获得configurationclasspostprocessor的beandefinition,rootbeandefinition是beandefinition的子类
      2. 执行registerpostprocessor方法,注册bean

    5 beandefinition是什么?

    spring-ioc源码_spring_10

    1. beanmetadataelement接口,beandefinition元数据,返回该bean的来源

    2. attributeaccessor接口,提供对beandefinition属性操作能力

      spring-ioc源码_spring_11

    3. 他是用来描述bean,里面存放着关于bean的一些列信息,比如bean的作用域,bean所对应的class,是否懒加载,是否primary等等。

    4. registerpostprocessor

      spring-ioc源码_晋升高级-spring_12

      这方法为beandefinition设置了role,ROLE_INFRASTRUCTURE代表这是spring内部的,并非用户定义的。然后又调用了registerBeandefinition方法,他的实现类是defaultlistablebeanfactory:

      spring-ioc源码_spring_13

      spring-ioc源码_spring_14

      从这里可以看出defaultlistablebeanfactory就是我们所说的容器,里面放着beandefinitionmap,beandifinitionnames,前者呢beanname做key,beandefinition做value,后者是个集合,里面放beanname。

      spring-ioc源码_构造方法_15

      ConfigurationClassPostProcessor实现了beandefinitionregistrypostprocessor接口,beandefinitionregistryPostProcessor又扩展了beanfactorypostprocessor接口,beanfactorypostprocessor是spring的扩展点之一,configurationclasspostprocessor是spring的重要类

      spring-ioc源码_spring_16

      除了注册configurationclass后置处理器还注册了其他bean,比如bean后置处理器,也是spring的扩展点之一。至此,实例化annotatedbeandefinitionreader reader完毕。

  5. 创建beandefinition扫描器,classpathbeandefinitionscanner

    1. 由于常规方法不会用到annotationconfigapplicationcontext里的scanner。这里的canner仅仅是为了程序员手动调用里面的scan方法
  6. 注册配置类为beandefinition: register(annotatedclasses)

    spring-ioc源码_spring_17

    1.  传入的参数是数组

    spring-ioc源码_spring_18

    spring-ioc源码_spring_19

    spring-ioc源码_构造方法_20

    这里需要注意的是以常规的方式去注册配置类,此方法除了第一个参数,其他参数都是默认值。

    1. 通过annotatedGenericBeanDefinition的构造方法,获取配置的bean定义,在注册configutationClass后置处理器也是通过构造方法获取bean定义,只是通过rootbeandefinition,现在是annotatedGenericBeanDefinition中获得
    2. 判断需不需要跳过注册,spring中有一个@Condition,如果不满足条件就会跳过这个类注册
    3. 解析作用域,如果没设置就默认为单例
    4. 获取beanname
    5. 解析通用注解,填充到annotatedGenericBeanDefinition,解析的注解为lazy,primary,dependsOn,role,Description
    6. 限定符处理,除了@Qualifier,还有primary,lazy
    7. 把annotatedGenericBeanDefinition数据结构和beanname封装到一个对象中
    8. 注册,最终会调用defaultlistableBeanFactory中的registerBeanDefinition方法注册

    spring-ioc源码_实例化_21

    spring-ioc源码_spring_22

    spring-ioc源码_晋升高级-spring_23


  7. refresh()方法

    spring-ioc源码_晋升高级-spring_24

    spring-ioc源码_晋升高级-spring_25

    spring-ioc源码_构造方法_26

    1. prepareRefresh

      主要是做一些刷新前的准备工作,和主流程关系不大,主要是保存容器的启动时间,启动标志

    2. configurablelistablebeanfactory beanfactory = obtainFreshBeanFactory()

      和主流程关系不大,主要是把beanfactory取出来,xml模式下到这里会读取beanDefinition

    3. prepareBeanFactory

      添加了俩个后置处理器 applicationContextAwareProcessor,applicationListenerDetector,还设置了忽略自动装配 和允许自动装配的接口,如果不存在某个bean的时候,spring就自动注册singleton Bean.以及bean表达式解析器

      spring-ioc源码_构造方法_27

      spring-ioc源码_实例化_28

      spring-ioc源码_实例化_29

      主要的操作如下

      1. 设置了类加载器
      2. 设置了bean表达式解析器
      3. 添加了属性编辑器的支持
      4. 添加了一个后置处理器:applicationContextAwareProcessor,此后置处理器实现了beanpostprocessor接口
      5. 设置了一些忽略自动装配的接口
      6. 设置了一些允许自动装配的接口,并且进行了复制操作
      7. 在容器中还没有xxbean的时候,帮我们注册beanName为xx的单例bean
    4. postProcessBeanFactory(beanFactory)

      空方法,以后可能会被扩展

    5. invokeBeanFactoryPostProcessors(BeanFactory)

      spring-ioc源码_构造方法_30

      看这个小方法

      spring-ioc源码_构造方法_31

      这里获得的是beanFactorypostprocessor,可以手动添加一个后置处理器,而不是交给spring去扫描

      spring-ioc源码_实例化_32

      只有这样,这个集合才不会为空。

      spring-ioc源码_实例化_33

      spring-ioc源码_实例化_34

      spring-ioc源码_晋升高级-spring_35

      spring-ioc源码_构造方法_36

      spring-ioc源码_晋升高级-spring_37

      spring-ioc源码_晋升高级-spring_38

      spring-ioc源码_实例化_39

      spring-ioc源码_构造方法_40

      spring-ioc源码_实例化_41

      spring-ioc源码_构造方法_42

      首先判断beanFactory是不是beandefinitionRegistry的实例,然后执行一下操作

      1. 定义一个set,装beanName,然后根据这个set,来判断后置处理器是否被执行过

      2. 定义俩个list,一个是regular后置处理器,用来装beanFactory后置处理器,一个是registryProcessors用来装载beanDefinitionRegistry后置处理器,其中bean定义注册后置处理器扩展了beanFactory后置处理器,bean定义注册后置处理器有俩个方法,一个是独有的后置处理器bean定义注册方法,一个是父类的后置处理器beanFactory方法

      3. 循环传入的beanfactory后置处理器,一般情况下都是空的,唯有手动加入beanFactory后置处理器。才有数据。因为bean定义注册后置处理器扩展了beanFactory后置处理器,所以这里要判断是不是bean定义注册后置处理器,是的话就执行后置处理器bean定义注册方法,然后把对象封装到registryprocessory中,不是的话就封装到regular后置处理器中

      4. 定义一个临时变量currentRegistryprocessors,用来装bean定义注册后置处理器

      5. getBeanNamesforType,通过类型找到beannames,从beanDefinitionNames去找,举个例子,如果这里传入了beanDefinitionregistryPostProcessor.class,就会找到类型为该类型的后置处理器。并且赋值给postProcessoryNames.一般情况下只会找到一个,就是internalconfigurationAnnotationProcessor,也就是confurationAnnotationProcess.如果你实现了bean定义后置处理器接口,也打上了@Component注解,但是在这里没有获取到,因为spring扫描实在configurationClass后置处理器类中完成的,也就是下面的invokeBeanDefinitionRegistry后置处理器方法。

      6. 循环postProcessorNames,是internalConfigurationAnnotationProcessor,判断此后置处理器是否实现了priorityordered接口。如果实现了,就把它添加到currentregistryProcessors中。再放入processedBeans,代表这个后置处理器已经被处理过了。

        spring-ioc源码_晋升高级-spring_43

      7. 进行排序,priorityOrdered是一个排序接口,如果实现了它说明后置处理器是有顺序的,要排序,目前只有configurationClass后置处理器

      8. 把currentRegistyprocessors合并到registryprocessors,因为一开始spirng只会执行beanDefinitionRegistry后置处理器的独有方法,而不执行父类方法,所以需要把这些后置处理器放入到一个集合中,后续统一执行beanFactoryProcessor接口中的方法。

      9. 可以理解为执行currentRegistryprocessors中的中的ConfigurationClass后置处理器中的postProcessBeanDefinitionRegistry方法,这里体现了spring的设计思想,热插拔。spring很多东西交给插件去做,如果不想用,就不添加

        spring-ioc源码_spring_44

      10. 清空currentRegistryProcessors,因为currentRegistryProcessors是一个临时变量,完成了目前的任务,所以清空,后面还会用到

      11. 再次根据bean定义注册后置处理器获得beanname,然后进行循环,看这个后置处理器是否被执行过了,如果没有执行,也实现了order接口,就把此后置处理器推送到currentRegistryprocessors和processedBean中。这里就可以获得我们定义的并且搭上了@Component注解的后置处理器。因为spring完成了扫描,但是需要注意由于ConfigurationClassPostProcessors上面已经被执行了,虽然可以通过getBeanNameForType获得,但是并不会加入到currentRegistryProcessors和processedBeanas.

      12. 处理排序

      13. 合并processors,合并的理由和上面一样

      14. 执行我们自定义的beandefinitionregistry后置处理器

      15. 临时清空变量

      16. 在上面的方法中,仅仅是执行了实现orderer接口的bean定义注册后置处理器,这里是执行没有实现ordered接口的bean定义注册后置处理器。

      17. 上面的代码时执行子类独有的方法,这里需要把父类的方法也执行一次

      18. 执行regular后置处理器中的后置处理器方法,需要注意的时,在一帮情况下,regular后置处理器,只有在外面手动添加beanFactory后置处理器才有数据。

      19. 查找实现了beanFactory后置处理器,并且执行了后置处理器中的方法。如下图

        spring-ioc源码_spring_45

        spring-ioc源码_晋升高级-spring_46

        spring-ioc源码_晋升高级-spring_47

        spring-ioc源码_实例化_48

        spring-ioc源码_实例化_49

        spring-ioc源码_实例化_50

        1. 获取所有的beanName,放入candidateNames数组
        1. 循环candidateNames数组,根据beanName获取beanDefinition,判断是否被处理过了。

        2. 判断是否是配置类,如果是,加入到configCandidates数组,在判断的时候还会标记配置类属于full还是lite配置类。

        3.1 当我们注册配置类的时候,可以加@Configuration,也可以加@Component,@ComponentScan,@Import,@ImportResource等注解,spring称这种配置为lite配置类,如果加了@Configuration就称之为full配置类。

        3.2 如果我们注册了lite配置类,getBean时会发现就是原本的配置类,如果我们注册full配置类,getbean时是一个cglib代理类。

        spring-ioc源码_晋升高级-spring_51

        spring-ioc源码_spring_52

        3.3 写一个A类,其中一个构造方法是打印”你好“ ,在一个配置类,有俩个被@Bean注解的方法,其中一个方法return new A(),命名为getA(),另一个方法调用getA(),如果配置类是lite配置类,会发现打印俩次你好,也就是说A类被new了俩次,如果配置类是Full类,会发现只打印一次”你好“,也就是说A类只被new了一次,因为这个类被cglib代理了,方法已经被改写。

spring-ioc源码_构造方法_53

spring-ioc源码_晋升高级-spring_54

spring-ioc源码_晋升高级-spring_55

spring-ioc源码_构造方法_56

spring-ioc源码_晋升高级-spring_57

  1. 递归处理内部类,一般不会使用内部类。
  2. 处理@PropertySource注解,@ProertySource注解用来加载properties文件
  3. 获得componentscan注解具体的内容,componentscan注解出了最常用的basePackage之外,还有includeFilters,excludeFilters等
  4. 判断有没有被@ComponentScans标记,或者被@Condition条件带过,如果满足条件的话,进入if,进行如下操作。
  1. 执行扫描操作,吧扫描出来的放入set.
  2. 循环set,判断是否是配置类,是的话递归调用parse方法,因为被扫描出来的类,还是一个配置类,有@ComponentScan注解,或者其中有被@Bean标记的方法,等等,所以需要被再次解析。
  1. 处理@Import注解,他有三种情况,一种是import普通类,一种是importSelector,还有一种是 importBeanDefinitionRegistrar,getImports(sourceClass)是获得import的内容,返回的是一个set
  2. 处理@ImportResource注解
  3. 处理@Bean的方法,可以看到获得了带有@Bean的方法后,不是马上转化称beanDefinition,而是先用一个set接受

spring-ioc源码_实例化_58

spring-ioc源码_构造方法_59

spring-ioc源码_spring_60

spring-ioc源码_晋升高级-spring_61

  1. 定义了一个扫描器scanner,常规方法中,实际上执行扫描只会是这里的scanner对象
  2. 处理includeFilters,就是把规则添加到scanner
  3. 处理excludeFilters,就是把规则添加到scanner.
  4. 解析basepackages,获得需要扫描哪些包。
  5. 添加一个默认的排除规则,拍出自己
  6. 执行扫描

这里有一个补充说明,添加规则的时候,只是把具体的规则放入规则类的集合中去,规则类是一个函数式接口,之定义了一个虚方法的接口被称为函数式接口,这里只是把规则放进去,并没有真正执行这些规则。

spring-ioc源码_实例化_62

spring-ioc源码_spring_63

因为basePackages可能有多个,所以需要循环处理,最终会进行bean的注册,看一下findCandidateComponents

spring-ioc源码_spring_64

spring支持component索引技术,需要引入一个组件,大部分项目没引进,索引会进入scanCandidateComponents方法

spring-ioc源码_晋升高级-spring_65

spring-ioc源码_构造方法_66

spring-ioc源码_实例化_67

spring-ioc源码_实例化_68

spring-ioc源码_构造方法_69

spring-ioc源码_spring_70

spring-ioc源码_spring_71

spring-ioc源码_spring_72

直到这里,才把configurationClassPostProcessor中的processConfigBeanDefinitions方法简单过一下,这里只会解析@Import的bean,不会注册。

processConfigBeanDefinitions是BeanDefinitionRegistryPostProcessor接口中的方法,beanDefinitionRegistry后置处理器扩展了beanfactoryPostProcessor.postProcessBeanFactory是判断配置类是lite还是full,如果是full就会被cglib代理,目的是保证bean的作用域

spring-ioc源码_实例化_73

总结:configurationClassPostProcessor中的processConfigBeanDefinitions主要是完成扫描,最终注册我们定义的bean.

6.6 registerBeanPostProcessors(beanFactory)

实例化和注册beanfactory中扩展了beanPostProcessor的bean.

例如autowriedAnnotationBeanPostProcessor(处理被@Autowired修饰的bean并注入)

requiredAnnotataionBeanPostProcessor(处理被@Requied注解修饰的方法)

commonAnnotationBeanPostProcessor(处理@PreDestory,@Resource等多个注解的作用)等

spring-ioc源码_实例化_74

6.7 initMessageSource()

初始国际化资源处理器

6.8 initapplicationEventMulticaster()

//创建事件多播器

spring-ioc源码_spring_75

6.9 onRefresh()

模板方法,在容器刷新的时候可以自定义逻辑,不同的spring容器做不同的事情

6.10 registerListeners()

注册监听器,广播early application events

6.11 finishBeanfactoryInitialization(Beanfactory)

实例化所有剩余的单例,懒加载除外

比如invokeBeanfactorypostprocessorts方法中根据注解解析出来的的类,在这个时候都会被初始化。

实例化的过程各种beanpostProcessor开始起作用。

spring-ioc源码_spring_76

上面这个方法是实例化懒加载单例bean的,也就是我们创建的bean

spring-ioc源码_晋升高级-spring_77

再看finishBeanFactoryInitialization这个方法,里面有一个beanFactory.preInstantiateSingletons()方法,顶进去之后一个接口,它的实现类是defaultListableBeanFactory,找到里面的getBean方法,这个方法 有一个分支,如果bean是fanctoryBean,对应处理。。。。如果bean不是factoryBean,对应处理。。。。不过不管是不是fanctoryBean最终都会调用getBean方法,直接调用doGetBean.

spring-ioc源码_构造方法_78

spring-ioc源码_spring_79

这里面有一个createBean方法,有一个实现类为abstractAutowireCapableBeanFactory

spring-ioc源码_构造方法_80

创建实例

spring-ioc源码_构造方法_81

填充属性

spring-ioc源码_构造方法_82

spring-ioc源码_构造方法_83

aware系列接口回调

spring-ioc源码_构造方法_84

spring-ioc源码_晋升高级-spring_85

spring-ioc源码_构造方法_86

spring-ioc源码_实例化_87

springBean的生命周期

网上流传的一段

  1. 实例化bean对象,没有属性,
  2. 填充属性
  3. 如果bean实现了beanNameaware接口,调用setBeanName方法
  4. 如果bean实现了beanClassLoaderAware接口,则调用setBeanClassLoader方法
  5. 如果bean实现了beanFactoryAware接口,调用setBeanFactory方法
  6. 调用beanpostProccessor的postProcessBeforeInitialization方法。
  7. 如果bean实现了initializingBean接口,调用afterPropertiesSet方法
  8. 如果bean定义了Initializating接口,调用bean的init-method
  9. 调用beanpostProcessor的postProcessAfterInitialization方法。进行到这里,bean已经准备就绪,停留在应用的上下文中,知道被销毁
  10. 如果上下文被销毁了,如果bean实现了disposableBean接口,则调用destory方法,如果bean定义了destory-method声明了销毁方法也会被调用
为了验证上面的逻辑,可以做个试验: 

首先定义了一个Bean,里面有各种回调和钩子,其中需要注意下,我在SpringBean的构造方法中打印了

studentService,看SpringBean被new的出来的时候,studentService是否被注入了;又在

setBeanName中打印了studentService,看此时studentService是否被注入了,以此来验证,Bean是何时

完成的自动注入的(这个StudentServiceImpl 类的代码就不贴出来了,无非就是一个最普通的Bean)

spring-ioc源码_实例化_88

spring-ioc源码_构造方法_89

spring-ioc源码_构造方法_90

spring-ioc源码_spring_91

spring-ioc源码_晋升高级-spring_92

spring-ioc源码_spring_93

6-12 finishRefresh()

refresh做完之后需要做的事情

清楚上下文资源缓存(如扫描中的asm元数据)

初始化上下文的生命周期处理器,并刷新。

发布contextRefreshedEvent事件并告知对应的applicationListener进行相应的操作

spring-ioc源码_spring_94

spring-ioc源码_实例化_95

spring-ioc源码_构造方法_96

spring-ioc源码_晋升高级-spring_97

2.使用时间广播器广播事件到相应的监听器multicastEvent

spring-ioc源码_spring_98

3.2调用监听器invokeListener

spring-ioc源码_spring_99

spring-ioc源码_spring_100

这样,当spring执行到finishrefresh方法时,就会将contextrefreshedEvent事件推送到myrefreshedListener中。跟contextRefreshedEvent相似的还有::ContextStartedEvent、ContextClosedEvent、

ContextStoppedEvent,有兴趣的可以自己看看这几个事件的使用场景。当然也可以自定义监听事件,只需要继承applicationContextEvent抽象类即可

不会,我可以学;落后,我可以追赶;跌倒,我可以站起来!