BeanFactory创建流程
获取BeanFactory
BeanFactory是spring框架中IOC容器的顶层接口,只是用来定义一些基础功能,定义一些基础规范,而ApplicationContext是它的一个子接口,所以ApplicationContext是具备BeanFactory提供的全部功能。
BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的高级接口,拥有更多的功能,比如说国际化支持和资源访问(xml,java配置类)等。
启动IOC容器的方式:
1)Java环境下启动IoC容器
·ClassPathXmlApplicationContext:从类的根路径下加载配置⽂件(推荐使⽤)
·FileSystemXmlApplicationContext:从磁盘路径上加载配置⽂件
·AnnotationConfigApplicationContext:纯注解模式下启动Spring容器
2)web环境下启动IOC容器
从xml启动容器
从配置类启动容器:
这里我们采用SpringIOC纯xml模式先定义一个applicationContext.xml配置bean相关信息
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd ">
<bean id="lagouBean" class="com.lagou.LagouBean"/>
<bean id="myBeanFactoryPostProcessor" class="com.lagou.MyBeanFactoryPostProcessor"/>
<bean id="beanTest" class="com.test.BeanTest"/> </beans>
创建com.test包,创建BeanTest类,定义id和name。
接下来在test包下,创建测试类,写测试方法如下:
@Test
public void testIoC() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
BeanTest beanTest = applicationContext.getBean(BeanTest.class);
System.out.println(beanTest );
}
接下来通过源码看IOC的初始化流程。根据断点调试,发现在未设置延迟加载的前提下,bean的创建是在容器初始化过程中完成的。
进入构造器中:
核心refresh方法
首先刷新前的预处理(不重点关注),重点红色框方法,功能:获取beanFactory,默认实现DefaultListableBeanFactory,加载BeanDefinition并注册到BeanDefitionRegistry
实例化DefaultListableBeanFactory,设置序列化id,自定义bean工厂的一些属性(是否覆盖、是否允许循环依赖),加载BeanDefinition
创建的时候DefaultListableBeanFactory中的部分定义
BeanDefinition加载解析及注册
进入到AbstractXmlApplicationContext类的loadBeanDefitions方法 并依次按着箭头走进入相应的loadBeanDefitions方法 , AbstractXmlApplicationContext —> AbstractBeanDefinitionReader —> XmlBeanDefinitionReader 一直执行到XmlBeanDefinitionReader 的doLoadBeanDefinitions 方法
resource定位:对BeanDefinitions资源定位过程,就是找到定义Javabean信息的xml文件,并封装成Resource对象
读取xml信息,将xml信息保存到document对象,并解析对象封装BeanDefinition并进行注册
重点关注XmlBeanDefinitionReader 的registerBeanDefinitions 方法,期间产生了多次重载调用,选择最后一个
来到DefaultBeanDefinitionDocumentReader类中的registerBeanDefinitions
进入doRegisterBeanDefinitions
BeanDefinitionParserDelegate中创建好的delegate
重点是parseBeanDefinitions ,它的前后两个方法都是钩子方法
重点进入parseDefaultElement ,解析bean元素,进入到具体处理方法processBeanDefinition
解析成BeanDefinitionHolder对象,try里完成注册
返回defaultBeanDefinitionDocumentReader继续执行
BeanDefinitionReaderUtils
DefaultListableBeanFactory
注册就是把xml中定义的bean信息封装为BeanDefinition对象放入一个map中
至此已经完成BeanDefinition的加载解析及注册子流程。
Bean创建流程
接着看下bean的创建流程。
首先分析存放bean信息的map集合,发现在DefaultListableBeanFactory类中有doGetBeanNameForType方法中用到。看到主要的代码为isTypeMatch这个方法。
通过断点查看当前singletonObjects存放的是实例化之后的Bean对象,此时为null, 通过这个关键字,查找singletonObjects什么时候不为空的,在AbstractAutowireCapableBeanFactory类中有put的过程,在此打断点,然后分析调用栈。
发现最终bean的创建是在AbstractApplicationContext#refresh() 的finishBeanFactoryInitialization方法,这个方法功能有初始化所有剩下的非懒加载的单例bean,初始化创建非懒加载方法的单例bean实例(未设置属性)----填充属性,初始化方法调用(比如调用afterPropertiesSet、init-method方法),调用BeanPostProcessor(后置处理器)对bean进行处理。
通过断点发现红色框部分代码就是实例化所有立即加载的单例bean。
红色框就是实例化bean的方法,注意如果是懒加载 情况下不会去getBean,
继续进⼊DefaultListableBeanFactory类的preInstantiateSingletons⽅法(实例化所有立即加载的单例bean),我们找到下⾯部分的代码,看到⼯⼚Bean或者普通Bean,最终都是通过getBean的⽅法获取实例
AbstractBeanFactory类中createBean继续追踪
AbstractAutowireCapableBeanFactory类中,重点关注两个方法一个是下面红色框已经创建bean实例,但是未设置属性。
第二是Bean属性填充,调用初始化方法,应用BeanPostProcessor后置处理器
进入initializeBean方法:
然后invokeInitMethods中
通过代码可以总结出bean的生命周期
lazy-init延迟加载机制
普通bean的初始化是在容器启动初始化阶段执行的,而被lazy-init=true修饰的bean,是在容器里第一次getBean时进行触发。spring启动的时候会把所有的bean信息解析转化成Spring能够识别的BeanDefinition并存入到map集合供初始化时用,然后对每个BeanDefinition进行处理,如果是懒加载则初始化阶段不处理,其他的在容器初始化阶段进行初始化并依赖注入。
看一下getBean的源码:
DefaultListableBeanFactory类中一直断点
直到进入AbstractBeanFactory类的doGetBean,此时如果不是懒加载会直接得到bean,如果是懒加载则得不到继续往下走
这里就会创建bean然后得到实例