spring-ioc源码
需要解决的问题
- beanfactory和factorybean的区别
- beanfactorypostprocessor在spring中的作用
- springioc的加载过程
- bean的生命周期
- spring中有哪些扩展接口及调用时机
大纲
1. 主要流程-springioc的加载过程
- 实例化容器AnnotationConfigApplicationContext
- 实例化工厂DefaultListAbleBeanFactory
- 实例化建立beanDefination读取器 annotatedBeandefinationReader
- 创建beandefination扫描器:classPathBeanDefiantionScanner
- 注册配置类为beanDefination: register方法,annotatedClasses
- refresh
- invokeBeanfacorypostProcessors(beanfactory)
- finishBeanfactoryinitialization(beanfactory)
2. 主要流程-spring bean的生命周期
springioc的加载过程
- 首先准备个例子如下(插入图片)
- 2.springioc的容器加载流程
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
annotationConfigApplicationContext的关系图如下
创建annotationConfigApplicationContext对象
首先看这个构造方法
3.4 如果没有配置类会字节返回
3.5 处理排序
3.6 解析配置类,可能是full类,也可能是lite类
3.7 在第六步的时候只是注册了部分Bean,但是如@Import@Bean,是没有被注册的。
因为可以有多个配置类,所以需要循环处理。我们的配置类的BeanDefinition是AnnotatedBeanDefinition的实例,所以会进入第一个
if
重点在于doProcessConfigurationClass方法,需要特别注意,最后一段代码,会把configClass放于一个map,
这是一个有参构造方法,可以接受多个配置类,不过一般情况只传入一个配置类。
这个配置类有俩种情况,一种是传统意义上的带@Configutarion注解的配置类,还有一种是带@Component,@import,@importResource等注解的配置类,在spring中前者被称为full配置类,后者叫lite配置类,也叫普通bean
查看这个this()方法都干了什么,如图
首先无参构造方法中就是对读取器read和扫描器进行了实例化,reader的类型是annotatedbeandefinitionReader,可以看出他是一个 bean定义读取器,scanner的类型是classpathbeandefinitionscanner,它仅仅是外面手动调用.scan方法,
实例化工厂:defaultListableBeanFactory
DefaultListableBeanFactory的关系图
defaultlistablebeanfactory是bean的工厂,是用来生产和获得bean。
实例化建beanDefinition读取器:annotatedbeandefinitionReader
主要负责俩件事
注册内置beanPostprocrssor
- 注册相关的beandefinition
回到annotationconfigapplicationcontext的无参构造方法,看annotatedbeandefinitionreader
这里beandefinitionregistry是annotationconfigapplicationcontext的实例,这里调用其他类构造方法
这个方法就是注册spring的内置的多个bean
判断容器内是否存在configurationclasspostprocessor bean
- 如果不存在,就通过rootBeanDefinition的构造方法获得configurationclasspostprocessor的beandefinition,rootbeandefinition是beandefinition的子类
- 执行registerpostprocessor方法,注册bean
5 beandefinition是什么?
beanmetadataelement接口,beandefinition元数据,返回该bean的来源
attributeaccessor接口,提供对beandefinition属性操作能力
他是用来描述bean,里面存放着关于bean的一些列信息,比如bean的作用域,bean所对应的class,是否懒加载,是否primary等等。
registerpostprocessor
这方法为beandefinition设置了role,ROLE_INFRASTRUCTURE代表这是spring内部的,并非用户定义的。然后又调用了registerBeandefinition方法,他的实现类是defaultlistablebeanfactory:
从这里可以看出defaultlistablebeanfactory就是我们所说的容器,里面放着beandefinitionmap,beandifinitionnames,前者呢beanname做key,beandefinition做value,后者是个集合,里面放beanname。
ConfigurationClassPostProcessor实现了beandefinitionregistrypostprocessor接口,beandefinitionregistryPostProcessor又扩展了beanfactorypostprocessor接口,beanfactorypostprocessor是spring的扩展点之一,configurationclasspostprocessor是spring的重要类
除了注册configurationclass后置处理器还注册了其他bean,比如bean后置处理器,也是spring的扩展点之一。至此,实例化annotatedbeandefinitionreader reader完毕。
创建beandefinition扫描器,classpathbeandefinitionscanner
- 由于常规方法不会用到annotationconfigapplicationcontext里的scanner。这里的canner仅仅是为了程序员手动调用里面的scan方法
注册配置类为beandefinition: register(annotatedclasses)
1. 传入的参数是数组
这里需要注意的是以常规的方式去注册配置类,此方法除了第一个参数,其他参数都是默认值。
- 通过annotatedGenericBeanDefinition的构造方法,获取配置的bean定义,在注册configutationClass后置处理器也是通过构造方法获取bean定义,只是通过rootbeandefinition,现在是annotatedGenericBeanDefinition中获得
- 判断需不需要跳过注册,spring中有一个@Condition,如果不满足条件就会跳过这个类注册
- 解析作用域,如果没设置就默认为单例
- 获取beanname
- 解析通用注解,填充到annotatedGenericBeanDefinition,解析的注解为lazy,primary,dependsOn,role,Description
- 限定符处理,除了@Qualifier,还有primary,lazy
- 把annotatedGenericBeanDefinition数据结构和beanname封装到一个对象中
- 注册,最终会调用defaultlistableBeanFactory中的registerBeanDefinition方法注册
refresh()方法
prepareRefresh
主要是做一些刷新前的准备工作,和主流程关系不大,主要是保存容器的启动时间,启动标志
configurablelistablebeanfactory beanfactory = obtainFreshBeanFactory()
和主流程关系不大,主要是把beanfactory取出来,xml模式下到这里会读取beanDefinition
prepareBeanFactory
添加了俩个后置处理器 applicationContextAwareProcessor,applicationListenerDetector,还设置了忽略自动装配 和允许自动装配的接口,如果不存在某个bean的时候,spring就自动注册singleton Bean.以及bean表达式解析器
主要的操作如下
- 设置了类加载器
- 设置了bean表达式解析器
- 添加了属性编辑器的支持
- 添加了一个后置处理器:applicationContextAwareProcessor,此后置处理器实现了beanpostprocessor接口
- 设置了一些忽略自动装配的接口
- 设置了一些允许自动装配的接口,并且进行了复制操作
- 在容器中还没有xxbean的时候,帮我们注册beanName为xx的单例bean
postProcessBeanFactory(beanFactory)
空方法,以后可能会被扩展
invokeBeanFactoryPostProcessors(BeanFactory)
看这个小方法
这里获得的是beanFactorypostprocessor,可以手动添加一个后置处理器,而不是交给spring去扫描
只有这样,这个集合才不会为空。
首先判断beanFactory是不是beandefinitionRegistry的实例,然后执行一下操作
定义一个set,装beanName,然后根据这个set,来判断后置处理器是否被执行过
定义俩个list,一个是regular后置处理器,用来装beanFactory后置处理器,一个是registryProcessors用来装载beanDefinitionRegistry后置处理器,其中bean定义注册后置处理器扩展了beanFactory后置处理器,bean定义注册后置处理器有俩个方法,一个是独有的后置处理器bean定义注册方法,一个是父类的后置处理器beanFactory方法
循环传入的beanfactory后置处理器,一般情况下都是空的,唯有手动加入beanFactory后置处理器。才有数据。因为bean定义注册后置处理器扩展了beanFactory后置处理器,所以这里要判断是不是bean定义注册后置处理器,是的话就执行后置处理器bean定义注册方法,然后把对象封装到registryprocessory中,不是的话就封装到regular后置处理器中
定义一个临时变量currentRegistryprocessors,用来装bean定义注册后置处理器
getBeanNamesforType,通过类型找到beannames,从beanDefinitionNames去找,举个例子,如果这里传入了beanDefinitionregistryPostProcessor.class,就会找到类型为该类型的后置处理器。并且赋值给postProcessoryNames.一般情况下只会找到一个,就是internalconfigurationAnnotationProcessor,也就是confurationAnnotationProcess.如果你实现了bean定义后置处理器接口,也打上了@Component注解,但是在这里没有获取到,因为spring扫描实在configurationClass后置处理器类中完成的,也就是下面的invokeBeanDefinitionRegistry后置处理器方法。
循环postProcessorNames,是internalConfigurationAnnotationProcessor,判断此后置处理器是否实现了priorityordered接口。如果实现了,就把它添加到currentregistryProcessors中。再放入processedBeans,代表这个后置处理器已经被处理过了。
进行排序,priorityOrdered是一个排序接口,如果实现了它说明后置处理器是有顺序的,要排序,目前只有configurationClass后置处理器
把currentRegistyprocessors合并到registryprocessors,因为一开始spirng只会执行beanDefinitionRegistry后置处理器的独有方法,而不执行父类方法,所以需要把这些后置处理器放入到一个集合中,后续统一执行beanFactoryProcessor接口中的方法。
可以理解为执行currentRegistryprocessors中的中的ConfigurationClass后置处理器中的postProcessBeanDefinitionRegistry方法,这里体现了spring的设计思想,热插拔。spring很多东西交给插件去做,如果不想用,就不添加
清空currentRegistryProcessors,因为currentRegistryProcessors是一个临时变量,完成了目前的任务,所以清空,后面还会用到
再次根据bean定义注册后置处理器获得beanname,然后进行循环,看这个后置处理器是否被执行过了,如果没有执行,也实现了order接口,就把此后置处理器推送到currentRegistryprocessors和processedBean中。这里就可以获得我们定义的并且搭上了@Component注解的后置处理器。因为spring完成了扫描,但是需要注意由于ConfigurationClassPostProcessors上面已经被执行了,虽然可以通过getBeanNameForType获得,但是并不会加入到currentRegistryProcessors和processedBeanas.
处理排序
合并processors,合并的理由和上面一样
执行我们自定义的beandefinitionregistry后置处理器
临时清空变量
在上面的方法中,仅仅是执行了实现orderer接口的bean定义注册后置处理器,这里是执行没有实现ordered接口的bean定义注册后置处理器。
上面的代码时执行子类独有的方法,这里需要把父类的方法也执行一次
执行regular后置处理器中的后置处理器方法,需要注意的时,在一帮情况下,regular后置处理器,只有在外面手动添加beanFactory后置处理器才有数据。
查找实现了beanFactory后置处理器,并且执行了后置处理器中的方法。如下图
1. 获取所有的beanName,放入candidateNames数组
循环candidateNames数组,根据beanName获取beanDefinition,判断是否被处理过了。
判断是否是配置类,如果是,加入到configCandidates数组,在判断的时候还会标记配置类属于full还是lite配置类。
3.1 当我们注册配置类的时候,可以加@Configuration,也可以加@Component,@ComponentScan,@Import,@ImportResource等注解,spring称这种配置为lite配置类,如果加了@Configuration就称之为full配置类。
3.2 如果我们注册了lite配置类,getBean时会发现就是原本的配置类,如果我们注册full配置类,getbean时是一个cglib代理类。
3.3 写一个A类,其中一个构造方法是打印”你好“ ,在一个配置类,有俩个被@Bean注解的方法,其中一个方法return new A(),命名为getA(),另一个方法调用getA(),如果配置类是lite配置类,会发现打印俩次你好,也就是说A类被new了俩次,如果配置类是Full类,会发现只打印一次”你好“,也就是说A类只被new了一次,因为这个类被cglib代理了,方法已经被改写。
- 递归处理内部类,一般不会使用内部类。
- 处理@PropertySource注解,@ProertySource注解用来加载properties文件
- 获得componentscan注解具体的内容,componentscan注解出了最常用的basePackage之外,还有includeFilters,excludeFilters等
- 判断有没有被@ComponentScans标记,或者被@Condition条件带过,如果满足条件的话,进入if,进行如下操作。
- 执行扫描操作,吧扫描出来的放入set.
- 循环set,判断是否是配置类,是的话递归调用parse方法,因为被扫描出来的类,还是一个配置类,有@ComponentScan注解,或者其中有被@Bean标记的方法,等等,所以需要被再次解析。
- 处理@Import注解,他有三种情况,一种是import普通类,一种是importSelector,还有一种是 importBeanDefinitionRegistrar,getImports(sourceClass)是获得import的内容,返回的是一个set
- 处理@ImportResource注解
- 处理@Bean的方法,可以看到获得了带有@Bean的方法后,不是马上转化称beanDefinition,而是先用一个set接受
- 定义了一个扫描器scanner,常规方法中,实际上执行扫描只会是这里的scanner对象
- 处理includeFilters,就是把规则添加到scanner
- 处理excludeFilters,就是把规则添加到scanner.
- 解析basepackages,获得需要扫描哪些包。
- 添加一个默认的排除规则,拍出自己
- 执行扫描
这里有一个补充说明,添加规则的时候,只是把具体的规则放入规则类的集合中去,规则类是一个函数式接口,之定义了一个虚方法的接口被称为函数式接口,这里只是把规则放进去,并没有真正执行这些规则。
因为basePackages可能有多个,所以需要循环处理,最终会进行bean的注册,看一下findCandidateComponents
spring支持component索引技术,需要引入一个组件,大部分项目没引进,索引会进入scanCandidateComponents方法
直到这里,才把configurationClassPostProcessor中的processConfigBeanDefinitions方法简单过一下,这里只会解析@Import的bean,不会注册。
processConfigBeanDefinitions是BeanDefinitionRegistryPostProcessor接口中的方法,beanDefinitionRegistry后置处理器扩展了beanfactoryPostProcessor.postProcessBeanFactory是判断配置类是lite还是full,如果是full就会被cglib代理,目的是保证bean的作用域
总结:configurationClassPostProcessor中的processConfigBeanDefinitions主要是完成扫描,最终注册我们定义的bean.
6.6 registerBeanPostProcessors(beanFactory)
实例化和注册beanfactory中扩展了beanPostProcessor的bean.
例如autowriedAnnotationBeanPostProcessor(处理被@Autowired修饰的bean并注入)
requiredAnnotataionBeanPostProcessor(处理被@Requied注解修饰的方法)
commonAnnotationBeanPostProcessor(处理@PreDestory,@Resource等多个注解的作用)等
6.7 initMessageSource()
初始国际化资源处理器
6.8 initapplicationEventMulticaster()
//创建事件多播器
6.9 onRefresh()
模板方法,在容器刷新的时候可以自定义逻辑,不同的spring容器做不同的事情
6.10 registerListeners()
注册监听器,广播early application events
6.11 finishBeanfactoryInitialization(Beanfactory)
实例化所有剩余的单例,懒加载除外
比如invokeBeanfactorypostprocessorts方法中根据注解解析出来的的类,在这个时候都会被初始化。
实例化的过程各种beanpostProcessor开始起作用。
上面这个方法是实例化懒加载单例bean的,也就是我们创建的bean
再看finishBeanFactoryInitialization这个方法,里面有一个beanFactory.preInstantiateSingletons()方法,顶进去之后一个接口,它的实现类是defaultListableBeanFactory,找到里面的getBean方法,这个方法 有一个分支,如果bean是fanctoryBean,对应处理。。。。如果bean不是factoryBean,对应处理。。。。不过不管是不是fanctoryBean最终都会调用getBean方法,直接调用doGetBean.
这里面有一个createBean方法,有一个实现类为abstractAutowireCapableBeanFactory
创建实例
填充属性
aware系列接口回调
springBean的生命周期
网上流传的一段
- 实例化bean对象,没有属性,
- 填充属性
- 如果bean实现了beanNameaware接口,调用setBeanName方法
- 如果bean实现了beanClassLoaderAware接口,则调用setBeanClassLoader方法
- 如果bean实现了beanFactoryAware接口,调用setBeanFactory方法
- 调用beanpostProccessor的postProcessBeforeInitialization方法。
- 如果bean实现了initializingBean接口,调用afterPropertiesSet方法
- 如果bean定义了Initializating接口,调用bean的init-method
- 调用beanpostProcessor的postProcessAfterInitialization方法。进行到这里,bean已经准备就绪,停留在应用的上下文中,知道被销毁
- 如果上下文被销毁了,如果bean实现了disposableBean接口,则调用destory方法,如果bean定义了destory-method声明了销毁方法也会被调用
为了验证上面的逻辑,可以做个试验:
首先定义了一个Bean,里面有各种回调和钩子,其中需要注意下,我在SpringBean的构造方法中打印了
studentService,看SpringBean被new的出来的时候,studentService是否被注入了;又在
setBeanName中打印了studentService,看此时studentService是否被注入了,以此来验证,Bean是何时
完成的自动注入的(这个StudentServiceImpl 类的代码就不贴出来了,无非就是一个最普通的Bean)
6-12 finishRefresh()
refresh做完之后需要做的事情
清楚上下文资源缓存(如扫描中的asm元数据)
初始化上下文的生命周期处理器,并刷新。
发布contextRefreshedEvent事件并告知对应的applicationListener进行相应的操作
2.使用时间广播器广播事件到相应的监听器multicastEvent
3.2调用监听器invokeListener
这样,当spring执行到finishrefresh方法时,就会将contextrefreshedEvent事件推送到myrefreshedListener中。跟contextRefreshedEvent相似的还有::ContextStartedEvent、ContextClosedEvent、
ContextStoppedEvent,有兴趣的可以自己看看这几个事件的使用场景。当然也可以自定义监听事件,只需要继承applicationContextEvent抽象类即可
不会,我可以学;落后,我可以追赶;跌倒,我可以站起来!