基于spring boot web项目分析
一、创建ApplicationContext
1. 构建beanFactory和ApplicationContext
ApplicationContext扩展了BeanFactory的功能,一些bean管理的核心功能使用BeanFactory实现。首先看这两个家伙的构建
1. create
从springboot的入口run进去,进入到createApplicationContext
首先根据容器的类型启动不同的applicationcontext,web的情况下选择AnnotationConfigServletWebServerApplicationContext,这个类的继承关系如下
进入到其父类GenericApplicationContext,可以看到初始化时构造了beanFactory
2. refresh
整体步骤在AbstractApplicationContext的refresh方法中
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// 1.构建BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
-
ComponentScan
我们自己定义的component、service等等,需要通过@ComponentScan指定basePackages,然后spring按照指定的包名去扫,将对应的类纳入容器。这一步主要是通过BeanFactoryPostProcessor实现,在refresh的invokeBeanFactoryPostProcessors中调用invokeBeanDefinitionRegistryPostProcessors
invokeBeanDefinitionRegistryPostProcessors
这里的BeanDefinitionRegistryPostProcessors是ConfigurationClassPostProcessor,这个类在createApplicationContext的时候就已经硬性的registerBeanDefinition进容器了,他的作用主要包括:
- 在postProcessBeanDefinitionRegistry()方法中解析了加了Configuration注解的类,同时解析出 @ComponentScan 和 @ComponentScans 扫描出的Bean,也会解析出加了 @Bean 注解的方法所注册的Bean,以及通过 @Import 注解注册的Bean和 @ImportResource 注解导入的配置文件中配置的Bean
- 在postProcessBeanFactory()方法中,会利用CGLIB对加了@Configuration注解的类创建动态代理,进行增强。最后还会向spring容器中添加一个Bean后置处理器:ImportAwareBeanPostProcessor
扫描后,BeanDefinition被放到BeanFactory中,等待下一步创建出来
-
创建Bean
从finishBeanFactoryInitialization开始,注释写着初始化所有剩下的非懒加载的单例。
finishBeanFactoryInitialization
进入到beanFactory的preInstantiateSingletons
preInstantiateSingletons
可以看到这里对beanDefinitionNames中的所有BeanDefinition进行了getBean操作。最终来到AbstractBeanFactory的doGetBean方法,方法的核心步骤如下图
doGetBean
首先是调用getSingleTon,并传入了一个匿名的Factory。getSingleTon在Factory创建Bean前后将beanName放入和移出singletonsCurrentlyInCreation。而Factory通过createBean方法创建Bean,然后通过getObjectForBeanInstance获得bean,这个方法可以理解为如果bean是FactoryBean就获取它创建的Bean,如果是Bean就直接获取自身。接下来看createBean方法
createBean
除了给BeanPostProcessors一个机会返回代理外,委托给了doCreateBean去处理
doCreateBean
doCreateBean做的事可以分成三部分,第一步是实例化Bean,第二步是把实例化后还没注入和初始化的Bean加入singletonFactory,第三步是注入和初始化Bean。
整体而言,创建Bean的流程是getBean -> doGetBean -> getSingleton -> createBean -> doCreateBean -
循环依赖
上面提到了singletonFactory,类似的还有singletonObjects、earlySingletonObjects,这些是Spring为解决循环依赖使用的三级缓存。- singletonObjects
一级缓存,完整的Bean就在这里,可以直接get使用。在getSingleton的最后会从二级缓存删除,放入一级缓存 - earlySingletonObjects
二级缓存。发生循环依赖时,在doGetBean时会从三级缓存取出放入二级缓存 - singletonFactory
三级缓存,以工厂形式提供Bean。 doCreateBean时放入
综上,首先放入的是三级缓存,如果有循环依赖会在get循环依赖的时候从三级缓存移入二级,然后在Bean彻底完整后移入一级缓存。现在看起来二级缓存好像没什么用,具体作用需要结合aop来分析。
如果没有aop,在A还没初始化完成的时候放入二级缓存,然后在populate时候去初始化B,然后拿到二级缓存中的A,完成B的初始化,注入A,这样A和B都正确地进行了初始化。
一旦加入aop,就会有个问题,aop是在初始化之后进行代理类植入,这样上面A中注入的B没有问题,而B中注入的A就不是代理类了。所以Spring引入三级缓存,三级缓存中加入的是一个创建Bean的工厂函数,返回调用的是getEarlyBeanReference,其中会创建aop的代理类放入二级缓存。
处理aop - singletonObjects
-
依赖注入
三种方式:- 构造器(官方推荐)
- 字段
- setter
官方推荐构造器的原因:
- 依赖不可变
- 依赖不为空
- 完全初始化的状态
依赖注入的时机
由AutowiredAnnotationBeanPostProcessor完成,这个类的三个方法AbstractAutowireCapableBeanFactory#doCreateBean
-> createBeanInstance
-> determineConstructorsFromBeanPostProcessors
-> AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors
-> autowireConstructor
-> ConstructorResolver#autowireConstructor
-> applyMergedBeanDefinitionPostProcessors
-> AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
-> populateBean
-> AutowiredAnnotationBeanPostProcessor#postProcessPropertyValuesdetermineCandidateConstructors继承自SmartInstantiationAwareBeanPostProcessor
postProcessMergedBeanDefinition继承自MergedBeanDefinitionPostProcessor
postProcessPropertyValues继承自InstantiationAwareBeanPostProcessor
第一个负责处理构造器注入,后两个分别负责构造注入的元数据和执行注入 -
AOP
-
时机
doCreateBean的最后,initializeBean中
applyBeanPostProcessorsAfterInitialization
在初始化完成后调用BeanPostProcessor的postProcessAfterInitialization
postProcessAfterInitialization -
AspectJAwareAdvisorAutoProxyCreator
Aop代理类的创建依赖BeanPostProcessor机制,以AspectJAwareAdvisorAutoProxyCreator为例
AspectJAwareAdvisorAutoProxyCreator
postProcessAfterInitialization在父类AbstractAutoProxyCreator中实现
wrapIfNecessary
wrap后,返回已经时为我们创建的代理类
-
二、spring bean的生命周期
参考
ConfigurationClassPostProcessor —— Spring中最!最!最!重要的后置处理器!没有之一!!!
理解 Spring(二):AOP 的概念与实现原理