从上一个博客可以看出spring中用于启动一个容器的类有这两大类:
1:AbstractRefreshableApplicationContext
2:GenericApplicationContext
本专题通过GenericApplicationContext 下的一个子类AnntationConfigretion来解读
第一步启动一个容器:
AnnotationConfigApplicationContext ect =new AnnotationConfigApplicationContext(TestMain.class);//标注了@Configration注解的类
那么Spring容器到底为我们做了什么呢? 我么追进源码中去看看:
首相从第一张类的继承树能够看出AnnotatonConfigApplicationCOntext 存在着一个GenericApplicationContext的父类所以在调用自身的构造方法之前一定会调用父类的构造方法。
请注意红框中标注出来的位置,这类指定的一个工厂对象为了更清楚不得不贴一下下面这张图:
所以AnnotationConfigAppliactionContext对象中持有一个DefaultListableBeanFactory对象所有的bean的定义信息都在他的bean定义信息的map中这个beanFactory在整个容器中流转
调用完父类的构造方法调用自身的构造方法:
1: 先调用自身的无参数的构造方法,这个特别重要:
在这个方法中会生成了两个特别重要的对象,一个reader对象,这个对象中会去加载一下spring内部的不许要事项的功能的组件比如:ConfigurationClassPostProcessor ,这是一个非常关键的类
这里是注入spring内部需要的组件由于篇幅原因只截取了部分
注意这个时候只是把bean的定义信息放入bean工厂的beanDefinitionMap 和beanDefinitionNames中到目前为止容器中还没有对应的对象。这一点特别重要?重要的事情说三遍 。 到了这 第一个方法就算执行完了
下面是ClassPathBeanDefinitionScanner对象的生成,这个对象定义了完spring容器中扫描的注解
到这无参数的构造方法执行完成,开始执行 register(annotatedClasses); annotatedClasses就是我们传入的配置类
前面说过registry是AnnotationConfigApplicationContext对象所有点进去看看:
在注入bean的定义信息的时候spring本身会做一些判断:
1.首先这个bena不是抽象的
2.判断容器中是否已近存在这个bean的定义信息了:
1.如果存在判断这个bean时候可以复写,如果不能直接抛异常,如果可以就抱着bean的定 义信息注入(直接覆盖原来的)
2.如果不存在: 判断这个bean的是有已经准备被创建了,如果没有就直接put进去。如果是 已近准备创建了 这有涉及到spring的循环依赖的问题
3.最后如果容器中有老的bean的定义信息,同时这个对象已经被穿件出来了,那么就需要重 置bean的定义信息
到这开始才是最难的部分:执行refresh()
1.prepareRefresh():
2.obtainFreshBeanFactory():这个方法简单就是获得DefaultListableBeanFactory
3.
4.
5.invokeBeanFactoryPostProcessors(beanFactory):这个方法特别难
这列由于篇幅的原因只取出部分代码:
这里存在一个BeanDefinitionRegistryPostProcessor 的执行顺序的问题
1.先执行使用@PriorityOrdered修饰的BeanDefinitionRegistryPostProcessor
2.在执行使用@Ordered修饰的BeanDefinitionRegistryPostProcessor
3.执行两种都没有使用的BeanDefinitionRegistryPostProcessor
4.执行使用@PriorityOrdered修饰BeanFactoryPostProcessor
5..执行使用@Ordered修饰BeanFactoryPostProcessor
6.最后执行什么都没有使用的
如果没有就直接返回了,如果存在,就通过@Order注解排序
先来看看parser方法:
各种Aware接口的回调
把ImprotSelector中返回的全类名,在一次递归调用,这个再一次检查时候是这几种接口,如果不是及当做一个Config配置是类处理调用processConfigurationClass,,然后循环Config配置类的解析过程
从上面的图片可以看出@Bean @Import 解析出来的bean 的定义信息没有被添加到容器中去
他们都是通过下面的方法导入的容器中的