Spring IoC源码剖析
# Spring IoC源码深度剖析
阅读源码原则:
- 定焦原则:抓主线
- 宏观原则:站在上帝视⻆,关注源码结构和业务流程,淡化具体某⾏代码的编写细节
阅读技巧:
- 打断点,观察调⽤栈
- 查反调,Find Usages
- 经验:Spring框架中doXXX,做具体处理的地⽅
Spring源码编译顺序:core->oxm->context->beans->aspects-aop,下文Spring源码基于5.3.x。
# Spring IoC容器初始化主流程
# Spring IoC的容器体系
IoC容器是Spring的核⼼模块,是抽象了对象管理、依赖关系管理的框架解决⽅案。Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器必须遵从的⼀套原则(基础行为),具体的容器实现可以增加额外的功能,⽐如我们常⽤到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容, AnnotationConfigApplicationContext 则是包含了注解解析等⼀系列的内容。Spring IoC 容器继承体系⾮常优雅,需要使⽤哪个层次⽤哪个层次即可,不必使⽤功能⼤⽽全的。
ApplicationContext
Spring应用上下文,官方称之为 IoC容器。通常一些人错误地认为:容器就是Map而已,但准确来说,Map是IoC容器的一个成员,叫做单例池, singletonObjects。而容器是一组组件和过程的集合,包括BeanFactory、单例池、BeanPostProcessor等以及之间的协作流程。
BeanFactory 顶级接⼝⽅法定义如下:
BeanFactory 顶级接⼝集成体系如下:
通过其接⼝设计,我们可以看到我们⼀贯使⽤的 ApplicationContext 除了继承BeanFactory的⼦接⼝,还继承了ResourceLoader、MessageSource等接⼝,因此其提供的功能也就更丰富了。下⾯我们以 ClasspathXmlApplicationContext 为例,深⼊源码说明 IoC 容器的初始化流程。
# Bean⽣命周期关键时机点
思路:创建几个SpringBean类 ,让其实现⼏个特殊的接⼝,并分别在接⼝实现的构造器、接⼝⽅法中断点,观察线程调⽤栈,分析出 Bean 对象创建和管理关键点的触发时机。
InitializingBean接口&ApplicationContextAware接口实现类-SpringBean:
public class SpringBean implements InitializingBean, ApplicationContextAware {
public SpringBean() {
System.out.println("SpringBean 构造器...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("SpringBean afterPropertiesSet...");
}
public void print() {
System.out.println("print方法业务逻辑执行");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("setApplicationContext...." + applicationContext);
}
}
BeanPostProcessor接口实现类-MyBeanPostProcessor:
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
System.out.println("MyBeanPostProcessor 实现类构造函数...");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("springBean".equals(beanName)) {
System.out.println("MyBeanPostProcessor postProcessBeforeInitialization 方法被调用中......");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("springBean".equals(beanName)) {
System.out.println("MyBeanPostProcessor postProcessAfterInitialization 方法被调用中......");
}
return bean;
}
}
BeanFactoryPostProcessor接⼝实现类-MyBeanFactoryPostProcessor
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
System.out.println("BeanFactoryPostProcessor的实现类构造函数...");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor的实现方法调用中......");
}
}
对应的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
">
<bean id="springBean" class="com.example.spring.learn.SpringBean"/>
<bean id="myBeanPostProcessor" class="com.example.spring.learn.MyBeanPostProcessor"/>
<bean id="myBeanFactoryPostProcessor" class="com.example.spring.learn.MyBeanFactoryPostProcessor"/>
</beans>
IoC 容器源码分析⽤例:
@Test
public void testIoC() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
SpringBean bean = applicationContext.getBean(SpringBean.class);
System.out.println(bean);
}
问题一:分析Bean的创建是在容器初始化时还是在getBean时?
根据断点调试,我们发现,在未设置延迟加载的前提下,Bean 的创建是在容器初始化过程中完成的
问题二:分析构造函数调⽤情况,观察调⽤栈。
通过如上观察,我们发现构造函数的调⽤时机在AbstractApplicationContext类refresh⽅法的finishBeanFactoryInitialization(beanFactory)处;
问题三:分析 InitializingBean 之 afterPropertiesSet 初始化⽅法调⽤情况
通过如上观察,我们发现 InitializingBean中afterPropertiesSet ⽅法的调⽤时机也是在AbstractApplicationContext类refresh⽅法的finishBeanFactoryInitialization(beanFactory);
下文打断点的方式类似,观察调用栈的方式,不重复截图赘述。
问题四:分析BeanFactoryPostProcessor 初始化和调⽤情况
分别在构造函数、postProcessBeanFactory ⽅法处打断点,观察调⽤栈,发现调用时机都在AbstractApplicationContext类refresh⽅法的invokeBeanFactoryPostProcessors(beanFactory);
问题五:分析 BeanPostProcessor 初始化和调⽤情况
分别在构造函数、postProcessBeanFactory ⽅法处打断点,观察调⽤栈,发现:
- BeanPostProcessor 初始化在AbstractApplicationContext类refresh⽅法的registerBeanPostProcessors(beanFactory);
- postProcessBeforeInitialization、postProcessBeforeInitialization 调⽤在AbstractApplicationContext类refresh⽅法的finishBeanFactoryInitialization(beanFactory);
总结:根据上⾯的调试分析,我们发现 Bean对象创建的⼏个关键时机点的调⽤都在AbstractApplicationContext 类 的 refresh ⽅法中,可⻅这个⽅法对于Spring IoC 容器初始化来说相当关键,汇总如下:
关键点 | 触发代码 |
---|---|
构造器 | refresh#finishBeanFactoryInitialization(beanFactory)(beanFactory) |
BeanFactoryPostProcessor 初始化 | refresh#invokeBeanFactoryPostProcessors(beanFactory) |
BeanFactoryPostProcessor ⽅法调⽤ | refresh#invokeBeanFactoryPostProcessors(beanFactory) |
BeanPostProcessor 初始化 | registerBeanPostProcessors(beanFactory) |
BeanPostProcessor ⽅法调⽤ | refresh#finishBeanFactoryInitialization(beanFactory) |
# [重点]Spring IoC容器初始化主流程
由上分析可知,Spring IoC 容器初始化的关键环节就在 AbstractApplicationContext#refresh() ⽅法中,我们查看 refresh ⽅法来俯瞰容器创建的主体流程,主体流程下的具体⼦流程我们后⾯再来讨论。
@Override
public void refresh() throws BeansException, IllegalStateException {
// 对象锁加锁
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
/* Step1: Prepare this context for refreshing.
* 刷新前的预处理,设置Spring容器启动时间、开启活跃状态、撤销关闭状态、验证环境信息里一些必须存在的属性等。
*/
prepareRefresh();
/* Step2: Tell the subclass to refresh the internal bean factory.
* 获取BeanFactory,默认实现是DefaultListableBeanFactory
* 加载BeanDefinition并注册到 BeanDefinitionRegistry
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/* Step3: Prepare the bean factory for use in this context.
* BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加载器等)
*/
prepareBeanFactory(beanFactory);
try {
/* Step4: Allows post-processing of the bean factory in context subclasses.
* BeanFactory准备工作完成后进行的后置处理工作
*/
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
/* Step5: Invoke factory processors registered as beans in the context.
* 实例化实现了BeanFactoryPostProcessor接口的Bean,并调用接口方法
*/
invokeBeanFactoryPostProcessors(beanFactory);
/* Step6: Register bean processors that intercept bean creation.
* 注册BeanPostProcessor(Bean的后置处理器),在创建Bean的前后等执行
*/
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
/* Step7: Initialize message source for this context.
* 初始化MessageSource组件, 国际化功能、消息绑定、消息解析
*/
initMessageSource();
/* Step8: Initialize event multicaster for this context.
* 初始化事件派发器
*/
initApplicationEventMulticaster();
/* Step9: Initialize other special beans in specific context subclasses.
* 子类重写这个方法,在容器刷新的时候可以自定义逻辑,如创建Tomcat,Jetty等WEB服务器
*/
onRefresh();
/* Step10: Check for listener beans and register them.
* 注册应用的监听器,及时注册实现了ApplicationListener接口的监听器Bean
*/
registerListeners();
/* Step11: Instantiate all remaining (non-lazy-init) singletons.
* 【重点】初始化所有剩下的非懒加载的单例Bean
* 1. 初始化创建非懒加载方式的单例Bean实例(未设置属性)
* 2. 填充属性
* 3. 初始化方法调用,比如afterPropertiesSet方法、init-method方法
* 4. 调用BeanPostProcessor后置处理器,对实例Bean进行后置处理
* */
finishBeanFactoryInitialization(beanFactory);
/* Step12: ast step: publish corresponding event.
* 完成context的刷新,主要调用LifecycleProcessor的onRefresh()方法,并发布事件(ContextRefreshEvent)
* */
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();
contextRefresh.end();
}
}
}
# BeanFactory创建流程
# 获取BeanFactory⼦流程
时序图如下:
# BeanDefinition加载解析及注册⼦流程
# 关键步骤:
- Resource定位:指对BeanDefinition的资源定位过程。通俗讲就是找到定义JavaBean信息的XML⽂件,并将其封装成Resource对象。
- BeanDefinition载⼊:把⽤户定义好的JavaBean表示为IoC容器内部的数据结构,这个容器内部的数据结构就是BeanDefinition。
- 注册BeanDefinition到IoC容器
# 过程分析
Step 1:⼦流程⼊⼝在
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
⽅法中:@Override protected final void refreshBeanFactory() throws BeansException { // 判断是否有bean factory if (hasBeanFactory()) { // 销毁 beans destroyBeans(); // 关闭 bean factory closeBeanFactory(); } try { // 实例化 DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); // 设置序列化id beanFactory.setSerializationId(getId()); // 自定义bean工厂的一些属性(是否覆盖、是否允许循环依赖) customizeBeanFactory(beanFactory); // !加载应用中的BeanDefinitions loadBeanDefinitions(beanFactory); // 赋值当前bean factory this.beanFactory = beanFactory; } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
Step 2:依次调⽤多个类的 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; } catch (BeanDefinitionStoreException ex) { // ...... } // 多个catch .... }
Step 3:我们重点观察XmlBeanDefinitionReader 类的 registerBeanDefinitions ⽅法:
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; }
此处我们关注两个地⽅:⼀个
createRederContext
⽅法,⼀个是 DefaultBeanDefifinitionDocumentReader类的registerBeanDefifinitions
⽅法,先进⼊createRederContext ⽅法看看:public XmlReaderContext createReaderContext(Resource resource) { return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, getNamespaceHandlerResolver()); } public NamespaceHandlerResolver getNamespaceHandlerResolver() { if (this.namespaceHandlerResolver == null) { this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); } return this.namespaceHandlerResolver; } protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() { ResourceLoader resourceLoader = getResourceLoader(); ClassLoader cl = (resourceLoader != null ? resourceLoader.getClassLoader() : getBeanClassLoader()); return new DefaultNamespaceHandlerResolver(cl); }
我们可以看到,此处 Spring ⾸先完成了 NamespaceHandlerResolver 的初始化。
我们再进⼊ registerBeanDefinitions ⽅法中追踪,调⽤了org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions ⽅法:
@Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; doRegisterBeanDefinitions(doc.getDocumentElement()); }
进⼊ doRegisterBeanDefinitions ⽅法:
@SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...) protected void doRegisterBeanDefinitions(Element root) { // 委托模式,创建一个委托类 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); // We cannot use Profiles.of(...) since profile expressions are not supported // in XML config. See SPR-12458 for details. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isDebugEnabled()) { logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } // 钩子函数 preProcessXml(root); // !解析BeanDefinition parseBeanDefinitions(root, this.delegate); // 钩子函数 postProcessXml(root); this.delegate = parent; }
进⼊ parseBeanDefinitions ⽅法:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { // !解析默认标签元素 parseDefaultElement(ele, delegate); } else { // 解析自定义标签元素 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
进入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); } // 嵌套beans处理 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
进⼊ processBeanDefinition ⽅法:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 解析bean元素为BeanDefinition,但此时包装成了BeanDefinitionHolder对象 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // 如果有自定义标签,则处理自定义标签 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // 完成BeanDefinition的注册 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
进入 registerBeanDefinition 方法(org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition):
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // ...... BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { // ...... this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { // ...... } } else { // !Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); } }
⾄此,注册流程结束,我们发现,所谓的注册就是把封装的 XML 中定义的 Bean信息封装为 BeanDefinition 对象之后放⼊⼀个Map中,BeanFactory 是以 Map 的结构组织这些BeanDefinition的。可以在DefaultListableBeanFactory中看到此Map的定义:
/** Map of bean definition objects, keyed by bean name. */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
# 时序图
# Bean创建流程
之前的文章讲过 Spring Bean的生命周期,这里我们结合源码分析一下:
通过最开始的关键时机点分析,我们知道Bean创建⼦流程⼊⼝在AbstractApplicationContext#refresh()⽅法的finishBeanFactoryInitialization(beanFactory) 处:
/* Step11: Instantiate all remaining (non-lazy-init) singletons.
* 【重点】初始化所有剩下的非懒加载的单例Bean
* 1. 初始化创建非懒加载方式的单例Bean实例(未设置属性)
* 2. 填充属性
* 3. 初始化方法调用,比如afterPropertiesSet方法、init-method方法
* 4. 调用BeanPostProcessor后置处理器,对实例Bean进行后置处理
* */
finishBeanFactoryInitialization(beanFactory);
进⼊finishBeanFactoryInitialization:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// ......
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有立即加载的bean
beanFactory.preInstantiateSingletons();
}
继续进⼊DefaultListableBeanFactory类的preInstantiateSingletons
⽅法,我们找到下⾯部分的代码,看到⼯⼚Bean或者普通Bean,最终都是通过getBean的⽅法获取实例:
@Override
public void preInstantiateSingletons() throws BeansException {
// ......
// 触发所有非延迟加载单例bean的初始化,主要步骤为getBean
for (String beanName : beanNames) {
// 合并父BeanDefinition对象
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// FactoryBean增加&前缀
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
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);
}
}
}
// ......
}
从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;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
进入org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean方法,我们可以发现doCreateBean:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ......
try {
// 真正创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
// ......
}
进⼊doCreateBean⽅法看看,该⽅法我们关注两块重点区域:
创建Bean实例,此时尚未设置属性
if (instanceWrapper == null) { // 创建Bean实例,仅调用构造方法,但尚未设置属性 (生命周期第一步) instanceWrapper = createBeanInstance(beanName, mbd, args); }
给Bean填充属性,调⽤初始化⽅法,应⽤BeanPostProcessor后置处理器
// 初始化bean实例 Object exposedObject = bean; try { // bean属性填充 populateBean(beanName, mbd, instanceWrapper); // 调用初始化方法,应用BeanPostProcessor后置处理器 exposedObject = initializeBean(beanName, exposedObject, mbd); }
# lazy-init 延迟加载机制原理
普通 Bean 的初始化是在容器启动初始化阶段执⾏的,⽽被lazy-init=true
修饰的 bean 则是在从容器⾥第⼀次进⾏context.getBean() 时进⾏触发。前面分析我们知道,Spring 启动的时候会把所有bean信息(包括XML和注解)解析转化成Spring能够识别的BeanDefinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个BeanDefinition 进⾏处理,如果是懒加载的则在容器初始化阶段不处理,其他的则在容器初始化阶段进⾏初始化并依赖注⼊。
@Override
public void preInstantiateSingletons() throws BeansException {
// ......
// 触发所有非延迟加载单例bean的初始化,主要步骤为getBean
for (String beanName : beanNames) {
// 合并父BeanDefinition对象
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 容器初始化阶段,不处理懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// FactoryBean增加&前缀
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
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);
}
}
}
// ......
}
通过源码追踪,我们发现懒加载getBean时候最终是通过DefaultListableBeanFactory#resolveBean,最终又回到前面分析的getBean方法对bean进行实例化:
private <T> NamedBeanHolder<T> resolveNamedBean(
String beanName, ResolvableType requiredType, @Nullable Object[] args) throws BeansException {
// 懒加载最后,又调用了getBean
Object bean = getBean(beanName, null, args);
if (bean instanceof NullBean) {
return null;
}
return new NamedBeanHolder<T>(beanName, adaptBeanInstance(beanName, bean, requiredType.toClass()));
}
总结:
- 对于被修饰为lazy-init的bean,Spring容器初始化阶段不会进⾏init并且依赖注⼊,当第⼀次进⾏getBean时候才进⾏初始化并依赖注⼊,对于⾮懒加载的bean,getBean的时候会从缓存⾥头获取,因为容器初始化阶段 Bean 已经初始化完成并缓存了起来。
# Spring IoC循环依赖问题
# 什么是循环依赖
循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A依赖于B,B依赖于C,C⼜依赖于A。注意,这⾥不是函数的循环调⽤,是对象的相互依赖关系。循环调⽤其实就是⼀个死循环,除⾮有终结条件。
Spring中循环依赖场景有:
- 构造器的循环依赖(构造器注⼊)
- Field 属性的循环依赖(set注⼊)
其中,构造器的循环依赖问题⽆法解决,只能拋出 BeanCurrentlyInCreationException 异常,在解决属性循环依赖时,Spring采⽤的是三级缓存,提前暴露对象的⽅法。
# 循环依赖处理机制
单例 bean 构造器参数循环依赖(⽆法解决)
prototype 原型 bean循环依赖(⽆法解决)
对于原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过setXxx⽅法产⽣循环依赖,Spring都会直接报错处理。
AbstractBeanFactory.doGetBean()⽅法:
if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); }
在获取bean之前如果这个原型bean正在被创建则直接抛出异常。原型bean在创建之前会进⾏标记这个beanName正在被创建,等创建结束之后会删除标记。
try { //创建原型bean之前添加标记 beforePrototypeCreation(beanName); //创建原型bean prototypeInstance = createBean(beanName, mbd, args); } finally { //创建原型bean之后删除标记 afterPrototypeCreation(beanName); }
总结:Spring 不⽀持原型 bean 的循环依赖。
单例bean通过setXxx或者@Autowired进⾏循环依赖
Spring 的循环依赖的理论依据基于 Java 的引⽤传递,当获得对象的引⽤时,对象的属性是可以延后设置的,但是构造器必须是在获取引⽤之前。Spring通过setXxx或者
@Autowired
⽅法解决循环依赖,其实是通过提前暴露⼀个ObjectFactory对象来完成的,简单来说就是ClassA在调⽤构造器完成对象初始化之后,在调⽤ClassA的setClassB⽅法之前就把ClassA实例化的对象通过ObjectFactory提前暴露到Spring容器中。Spring容器初始化ClassA通过构造器初始化对象后提前暴露到Spring容器, AbstractAutowireCapableBeanFactory#doCreateBean中关键代码:
// 循环依赖处理,三级缓存 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //将初始化后的对象提前已ObjectFactory对象注⼊到容器中 addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); }
addSingletonFactory的方法:
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { // 暴露到三级缓存,singletonFactory 为lambda表达式 this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
例如,ClassA和ClassB互相依赖,
- ClassA调⽤setClassB⽅法,Spring⾸先尝试从容器中获取ClassB,此时ClassB不存在Spring容器中。
- Spring容器初始化ClassB,同时也会将ClassB提前暴露到Spring容器中
- ClassB调⽤setClassA⽅法,Spring从容器中获取ClassA ,因为第⼀步中已经提前暴露了ClassA,因此可以获取到ClassA实例
- ClassA通过spring容器获取到ClassB,完成了对象初始化操作。
这样ClassA和ClassB都完成了对象初始化操作,解决了循环依赖问题。