一.源码的简单设计思想:
对象谁创建的?->Spring容器
对象如何创建?
Spring是随随便便创建对象吗?不是
这就是BeanDefinition
在解析xml文件或解析注解时,方式肯定是不一样的,能不能给出一个抽象层?这便是读取器
当我们容器有这些bean定义信息,紧接着就可以做bean的对象实例化
当一个对象创建完成后,它经历了几个过程?一般我们描述中直接就说实例化,但实际包含两个步骤
在bean定义信息到BeanFactory的中间是不是可以有一个类似拦截器的东西,我可以把这些bean定义信息拦截下来从而可以进行修改,当然这里它不叫做拦截器,而是后置处理器 BeanFactoryPostProcessor,而且不止一个。
Bean的生命周期:
如果当前这个对象想获取到当前容器的某些属性值的时候,就需要实现这些aware接口。
另外再提一点,Bean实例化完成后,我要做一些事;Bean初始化完成后,我要做一些事。。。这样怎样实现?
二.一头扎进源码的海洋
从经典的refresh()开始:
根据上面所说,如果我们来写源码,第一步应该先做什么?读取配置文件。但是读取配置文件需要先有BeanFactory,没有容器,读取了也没地方放啊。
1.创建BeanFactory
顺便提下这里的prepareRefresh()只是些前戏准备。
2.加载bean定义信息
AbstractRefreshableApplicationContext#loadBeanDefinitions有AbstractXmlApplicationContext和XmlWebApplicationContext实现,这两个类都是AbstractRefreshableWebApplicationContext的子类。先看AbstractXmlApplicationContext的实现。
先创建一个XmlBeanDefinition读取器。
一个是获取资源,一个是获取定位。看下定位不为空之后执行的方法。
ResourceLoader用来加载资源的,将定位信息转为资源信息。如果是resource就没有这一步骤。下面有个分支,是否可以解析。
一定可以解析,因为:
当前上下文是ResourcePatternResolver的实例。
最终绕一圈还是回到直接加载资源的方法。
用Set来防止重复加载Resource。
Document是通过JDK自带的DocumentBuilder机械InputSource得到的。
解析默认的元素标签,如<beans/>,<bean />,<import />,<alias />,每一种标签都有对应的方法。
BeanDefinitionRegistry是与保存bean定义信息有关的接口,对bean定义信息的增删改查就是通过该接口。
最终将bean定义信息存在ConcurrentHashMap中,key为beanName。
最后发布注册完成事件。
prepareBeanFactory() 主要是准备了spring提供的bean增强工具。
3.执行BeanFactoryPostProcessor
先对beanFactory做一些准备工作,set一些属性。
postProcessBeanFactory(beanFactory)留给子类进行扩展工作的。
invokeBeanFactoryPostProcessors()
执行所有已注册的BeanFactoryPostProcessors
为什么必须要在实例化前调用? 因为对工厂增强的很多的东西都是为了实例化bean用的。
对BeanFactoryPostProcessor进行分类,通过registryProcessor.postProcessBeanDefinitionRegistry(registry)进行回调,完成注册。如果不是BeanDefinitionRegistryPostProcessor,继续分类。
(1)通过beanFactory.getBeanNameForType,以空间换时间。
接着对currentRegistryProcessor进行排序。
invokeBeanDefinitionRegistryPostProcessors()
排好序了,便逐个调用。
用完就清空。
上面是优先级较高的 PriorityOrdered, 接着是 ordered,过程一致。
这里其实可以优化,多一个list即可,为什么要遍历两遍呢?
最后 处理其他的 BeanDefinitionRegistryPostProcessors
最后调用postProcessBeanFactory
接着看registerBeanPostProcessors(),注册BeanPostProcessors,其方法逻辑和invokeBeanFactoryPostProcessors()大致相同。BeanPostProcessor 是针对 bean 的扩展,主要用在 bean 实例化之后,执行初始化方法前后,允许开发者对 bean 实例进行修改。
这里可以顺便提一下,
@AutoWired起作用依赖AutowiredAnnotationBeanPostProcessor,@Resource依赖CommonAnnotationBeanPostProcessor,这俩都是BeanPostProcessor的实现。
- 与invokeBeanFactoryPostProcessors 不同的是,invokeBeanFactoryPostProcessors 方法会直接调用 BeanFactoryPostProcessor 实现类的方法,而 registerBeanPostProcessors 方法只是将 BeanPostProcessor 实现类注册到 BeanFactory 的 beanPostProcessors 缓存中。这是因为,此时还未到 BeanPostProcessor 实现类“出场的时候”。
- BeanPostProcessor 实现类具体的 “出场时机” 在创建 bean 实例时,执行初始化方法前后。postProcessBeforeInitialization 方法在执行初始化方法前被调用,postProcessAfterInitialization 方法在执行初始化方法后被调用。
- BeanPostProcessor 实现类和 BeanFactoryPostProcessor 实现类一样,也可以通过实现 PriorityOrdered、Ordered 接口来调整自己的优先级。
4.调用反射机制进行bean的实例化
先注册BeanPostProcessors,只是注册没有执行。
initMessageSource进行国际化。
initApplicationEventMulticaster()初始化事件多播器,提前将事件发布器准备好。
onRefresh()留给子类扩展实现。
registerListeners() 注册事件监听器。以上都是做些实例化的准备工作。
紧接着就开始实例化过程了,
设置转换器。
直接到最后一行
遍历所有的bean定义信息,先判断当前bean对象是否是抽象的,是否是单例的,是否是懒加载的。
再判断当前bean对象是否实现了FactoryBean接口。没有实现,则直接跳到getBean();
以do开头都是核心方法
用实例包装类接收创建bean实例
使用简单的无参构造器
到达终点,实例化最底层
createBeanInstance只是在堆里开辟了一段空间,还没有完成对属性的赋值。
属性填充
5.执行BeanPostProcessors
属性填充后继续往下走,先调用实现了aware接口的方法。
接着执行BeanPostProcessor的postProcessBeforeInitialization()
接着执行我们自定义的init-method方法。
最后执行BeanPostProcessor的postProcessAfterInitialization()
6.执行finishRefresh()