Spring IOC容器初始化主体流程
Spring IOC的容器体系
IOC容器时Spring的核心模块,是抽象了对象管理、依赖关系管理的框架解决方案。
Spring 提供了很多的容器,其中BeanFactory是顶层容器(根容器),不能被实例化,它定义了所有的IOC容器必须遵从的一套原则,具体的容器实现可以增加额外的功能。
比如我们常用到的ApplicationContext,其下更具体的实现如 ClassPathXMLApplicationContext包含了解析xml等一系列的内容。
AnnotationConfigApplicationContext则是包含了注解解析等一系列的内容。Spring IOC容器继承体系设计得非常游侠,需要使用哪个接口实现哪个接口即可,不必实现一个功能复杂的大接口。
BeanFactory顶级接口的方法如下:
BeanFactory 容器继承体系:
通过其接口设计,我们可以看到我们一贯使用的ApplicationContext除了继承BeanFactory的子接口,还继承了ResourceLoader、MessageSource等接口,因此其提供的功能也就更丰富了。
下面我们以ClassPathXmlApplicationContext 为例,深入源码说明IOC容器的初始化流程
Bean生命周期关键时机点
思路:创建一个MyBean,让其实现几个特殊的接口,并分别在接口实现的构造器、接口方法中断点,观察线程调用栈,分析出Bean对象创建和管理关键点的触发时机
MyBean类:
public class MyBean implements InitializingBean {
private int id;
private String name;
public MyBean() {
System.out.println("构造器执行了......");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet执行了......");
}
}
MyBeanFactoryPostProcessor 后置处理器工厂实现类:
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor(){
System.out.println("MyBeanFactoryPostProcessor的构造函数......");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor的实现方法调用了......");
}
}
MyBeanPostProcessor 后置处理器实现类:
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
System.out.println("MyBeanPostProcessor构造方法调用了......");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("myBean".equals(beanName)){
System.out.println("MyBeanPostProcessor的before方法调用了......");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("myBean".equals(beanName)){
System.out.println("MyBeanPostProcessor的after方法调用了......");
}
return bean;
}
}
applicationContext.xml
<?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="myBean" class="com.myspring.demo.MyBean">
</bean>
<bean id="myBeanPostProcessor" class="com.myspring.demo.MyBeanPostProcessor"/>
<bean id="myBeanFactoryPostProcessor" class="com.myspring.demo.MyBeanFactoryPostProcessor"/>
</beans>
测试代码:
public class MyTest {
@Test
public void MySpringTest(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
MyBean myBean = (MyBean) applicationContext.getBean("myBean");
System.out.println(myBean);
}
}
我们在MyTest 的 MyBean myBean = (MyBean) applicationContext.getBean("myBean");
这行代码打断点:
-
分析Bean的创建是在容器初始化还是在getBean时:
-
根据断点调试,我们发现,在未设置延迟加载的前提下,Bean的创建是在容器初始化过程中完成的
-
分析构造函数的调用情况:
在MyBean的构造函数打上断点,debug运行,我们发现构造函数的调用时机是在 AbstractApplicationContext类中的refresh()方法里面调用了finishBeanFactoryInitialization()方法 处
-
分析 MyBean 实现的InitializingBean 接口实现方法afterPropertiesSet 初始化方法调用情况
在 System.out.println("afterPropertiesSet执行了......");
打上断点,我们观察调用栈,MyBean 实现的InitializingBean 接口实现方法afterPropertiesSet 初始化方法的调用时机也是在AbstractApplicationContext类中的refresh()方法里面调用了finishBeanFactoryInitialization()方法 处
-
SpringBean工厂的后置处理器的BeanFactoryPostProcessor的构造器、postProcessBeanFactory方法是哪个方法调用的?
方法同上,在对应代码出打上断点,debug运行,观察调用栈,发现是在
AbstractApplicationContext#refresh()#invokeBeanFactoryPostProcessors 处调用的
-
SpringBean的后置处理器BeanPostProcessor的构造方法是哪个方法调用的?
AbstractApplicationContext#refresh()#registerBeanPostProcessors 处调用的
-
SpringBean的后置处理器BeanPostProcessor的Before和after方法是哪个方法调用的?
AbstractApplicationContext#refresh()#finishBeanFactoryInitialization 处调用的
总结:
根据上面的调试分析,我们发现Bean对象创建的几个关键时机点代码层级的调用都在 AbstractApplicationContext 类 的 refresh 方法中,可见这个方法对于SpringIOC容器初始化来说相当关键,汇总如下:
关键点 |
触发代码 |
构造函数 |
refresh#finishBeanFactoryInitialization(beanFactory)(beanFactory) |
BeanFactoryPostProcessor 初始化 |
refresh#invokeBeanFactoryPostProcessors(beanFactory) |
BeanFactoryPostProcessor ⽅法调⽤ |
refresh#invokeBeanFactoryPostProcessors(beanFactory) |
BeanPostProcessor 初始化 |
registerBeanPostProcessors(beanFactory) |
BeanPostProcessor ⽅法调⽤ |
refresh#finishBeanFactoryInitialization(beanFactory) |
SpringIOC容器初始化主流程
由上分析可知,SpringIOC容器初始化的关键环节就在 **AbstractApplicationContext#refresh() **方法中,我们查看refresh方法来俯瞰容器创建的主题流程。
@Override
public void refresh() throws BeansException, IllegalStateException {
// 对象锁加锁 refresh()、registerShutdownHook()、close()时加锁
synchronized (this.startupShutdownMonitor) {
/*
Prepare this context for refreshing.
刷新前的预处理
表示在真正做refresh操作之前需要准备做的事情:
设置Spring容器的启动时间
开启活跃状态,撤销关闭状态
验证环境信息里一些必须存在的属性等
*/
prepareRefresh();
/*
Tell the subclass to refresh the internal bean factory.
获取BeanFactory,默认实现是DefaultListableBeanFactory
加载BeanDefinition 并注册到BeanDefinitionRegistry
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/*
Prepare the bean factory for use in this context.
BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加载器等)
*/
prepareBeanFactory(beanFactory);
try {
/*
Allows post-processing of the bean factory in context subclasses.
BeanFactory准备工作完成后的后置处理工作
*/
postProcessBeanFactory(beanFactory);
/*
Invoke factory processors registered as beans in the context.
实例化实现了BeanFactoryPostProcessor接口的bean,并调用接口方法
*/
invokeBeanFactoryPostProcessors(beanFactory);
/*
Register bean processors that intercept bean creation.
注册BeanPostProcessor(Bean的后置处理器),在创建Bean的前后等执行
*/
registerBeanPostProcessors(beanFactory);
/*
Initialize message source for this context.
初始化MessageSource组件(做国际化功能:消息绑定,消息解析)
*/
initMessageSource();
/*
Initialize event multicaster for this context.
初始化事件派发器
*/
initApplicationEventMulticaster();
/*
Initialize other special beans in specific context subclasses.
子类重写这个方法,在容器刷新的时候可以自定义逻辑;如创建Tomcat、jetty等web服务器
*/
onRefresh();
/*
Check for listener beans and register them.
注册应用的监听器,就是注册实现了ApplicationListener接口的监听器bean
*/
registerListeners();
/*
Instantiate all remaining (non-lazy-init) singletons.
初始化所有剩下的非延迟加载的单例bean
初始化创建非延迟加载的单例bean实例(未设置属性)
填充属性
初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)
调用BeanPostProcessor(后置处理器)对实例bean进行后置处理
*/
finishBeanFactoryInitialization(beanFactory);
/*
Last step: publish corresponding event.
完成context的刷新。主要调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent)
*/
finishRefresh();
}
......
}
}
BeanFactory创建流程
获取BeanFactory子流程
时序图如下:
BeanDefinition加载解析及注册子流程
-
该子流程涉及到如下几个关键步骤:
- Resource定位:指对BeanDefinition 的资源定位过程。通俗讲就是找到定义JavaBean信息的xml文件,并将其封装成Resource对象
- BeanDefinition 载入:把用户定义好的JavaBean表示为IOC容器内部的数据结构,这个容器内部是数据结构就是BeanDefinition
- 注册BeanDefinition 到IOC容器
-
过程分析
-
step1:子流程入口在 AbstractRefreshableApplicationContext#refreshBeanFactory 方法中
@Override
protected final void refreshBeanFactory() throws BeansException {
// 判断是否已有BeanFactory
if (hasBeanFactory()) {
// 销毁 beans
destroyBeans();
// 关闭 BeanFactory
closeBeanFactory();
}
try {
// 实例化 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置序列化ID
beanFactory.setSerializationId(getId());
// 自定义bean工厂的一些属性(是否覆盖、是否允许循环依赖)
customizeBeanFactory(beanFactory);
// 加载应用中的BeanDefinition
loadBeanDefinitions(beanFactory); // 注意这里就是入口
// 赋值
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
-
step2:依次调用多个类的 loadBeanDefinitions 方法 —> AbstractXmlApplicationContext —> AbstractBeanDefinitionReader —> XmlBeanDefinitionReader ⼀直执行到 XmlBeanDefinitionReader 的 doLoadBeanDefinitions 方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 读取xml信息,将xml信息保存到Document对象
Document doc = doLoadDocument(inputSource, resource);
// 解析document对象,封装BeanDefinition对象并进行注册
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
}
-
step3:我们重点观察XMLBeanDefinitionReader 类的 registerBeanDefinition 方法,期间产生了多次重载调用,我们定位到最后一个
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取已有BeanDefinition的数量
int countBefore = getRegistry().getBeanDefinitionCount();
// 注册BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 返回新注册的BeanDefinition
return getRegistry().getBeanDefinitionCount() - countBefore;
}
此处我们关注两个地方:createReaderContext
和 registerBeanDefinitions
-
createReaderContext
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,this.sourceExtractor, this, getNamespaceHandlerResolver());
}
/**
* Lazily create a default NamespaceHandlerResolver, if not set before.
* @see #createDefaultNamespaceHandlerResolver()
*/
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return this.namespaceHandlerResolver;
}
/**
* Create the default implementation of {@link NamespaceHandlerResolver} used if none is specified.
* <p>The default implementation returns an instance of {@link DefaultNamespaceHandlerResolver}.
* @see DefaultNamespaceHandlerResolver#DefaultNamespaceHandlerResolver(ClassLoader)
*/
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
return new DefaultNamespaceHandlerResolver(cl);
}
我们可以看到,此处Spring首先完成了 NamespaceHandlerResolve 的初始化
-
我们再进入 registerBeanDefinitions 方法中追踪,调用了 DefaultBeanDefinitionDocumentReader#registerBeanDefinitions 方法
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
进入 doRegisterBeanDefinitions
方法:
protected void doRegisterBeanDefinitions(Element root) {
......
preProcessXml(root);
parseBeanDefinitions(root, this.delegate); // 重点
postProcessXml(root);
this.delegate = parent;
}
进入 parseBeanDefinitions
方法后再进入 parseDefaultElement
方法:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// import元素处理
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// alias元素处理
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// bean元素处理
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate); // 这里就是解析bean元素
}
// 嵌套beans处理
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
进入 processBeanDefinition
方法:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析bean元素为BeanDefinition,但是此时使用 BeanDefinitionHolder 又包装成了 BeanDefinitionHolder对象
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/*
<bean id="myBean" class="com.myspring.demo.MyBean">
<property name="beanName" value="bean demo"/>
<meta key="demo" value="demo"/>
<mybean:username="mybean"/>
</bean>
如果有自定义标签,则处理自定义标签
*/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 完成BeanDefinition的注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
......
}
}
至此,注册流程结束,我们发现,所谓的注册就是把封装的XML中定义的Bean信息封装为BeanDefinition对象后放入一个Map中,BeanFactory 是以Map的结构组织这些BeanDefinition的。
可以在 DefaultListableBeanFactory#registerBeanDefinition
看到此Map的定义
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
Bean创建流程
通过最开始的关键时机点分析,我们知道Bean创建子流程入口在 AbstractApplicationContext#refresh()⽅法的finishBeanFactoryInitialization(beanFactory)
处
@Override
public void refresh() throws BeansException, IllegalStateException {
......
/*
Instantiate all remaining (non-lazy-init) singletons.
初始化所有剩下的非懒加载的单例bean
初始化创建非懒加载的单例bean实例(未设置属性)
填充属性
初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)
调用BeanPostProcessor(后置处理器)对实例bean进行后置处理
*/
finishBeanFactoryInitialization(beanFactory); // bean创建入口
......
}
进入finishBeanFactoryInitialization
方法
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
......
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有立即加载的单例bean
beanFactory.preInstantiateSingletons();
}
继续进入 DefaultListableBeanFactory
类的 preInstantiateSingletons
方法:
@Override
public void preInstantiateSingletons() throws BeansException {
......
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
// 实例化当前bean
getBean(beanName);
}
......
}
可以看到工厂bean或者普通bean,最终都是通过 getBean 的方法获取实例
继续跟踪下去,我们进入到了 AbstractBeanFactory#doGetBean
方法,这个方法中的代码很多,我们直接找到核心部分
// 创建单例bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
接着进入到 AbstractAutowireCapableBeanFactory#createBean()
方法
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
进入 doCreateBean
方法看看,该方法我们关注两块重点区域
if (instanceWrapper == null) {
// 创建bean实例,但是尚未设置属性
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 初始化bean实例
Object exposedObject = bean;
try {
// bean属性填充
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法,应用BeanPostProcessor后置处理器
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
到此,SpringIOC容器的初始化流程源码大概就看完了,源码内容非常多,调试起来还是有点懵的,建议多debug几次,不用看每一行代码,只需看下每个函数的主要功能即可。