Spring Framework 7.0.9 深度剖析-06-Bean 生命周期与依赖注入原理
1. 本章导读
在整个 Spring Framework 中,没有任何一个话题比"Bean 是怎么被创建出来的"更核心、也更容易被误解。日常开发中我们写一个 @Component,容器启动时它就出现了;但只要追问一句------"这个对象到底是在哪一行 new 出来的?它的依赖是在哪一行被赋值的?为什么两个互相 @Autowired 的单例不会必然报错?为什么构造器互相注入就一定报错?"------绝大多数开发者都答不上来。本章的目标,就是带着读者沿着 getBean → createBean → doCreateBean → populateBean → initializeBean → registerDisposableBean → destroySingletons 这条完整调用链,把 Spring Framework 7.0.9 中 Bean 生命周期的每一个关键方法逐行拆开。
本章涉及的模块与核心类如下(路径均相对仓库根目录 spring-framework-7.0.9):
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java:doGetBean主流程,是"按名字拿 Bean"的总入口。spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java:createBean/doCreateBean/createBeanInstance/populateBean/initializeBean,是真正"造对象"的地方。spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java:单例注册表,三级缓存、创建中标记、销毁回调都在这里。spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java:resolveDependency/doResolveDependency,是依赖注入"按类型找 Bean"的决策中心。spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java:处理@Autowired/@Value,并负责推断候选构造器。spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java:@Lazy注入代理的生成处。spring-context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java:把ApplicationContext、Environment、ResourceLoader等容器内建引用注入给 Aware 接口实现。spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java:把@PreDestroy、DisposableBean.destroy()、自定义destroy-method统一成一个可执行的销毁任务。
前置知识:读者应当已经会用 @Configuration + @ComponentScan 启动一个容器,知道 BeanFactory 与 ApplicationContext 的基本区别,了解 BeanPostProcessor 的两个回调方法大致在什么时候执行。本章不假设读者读过本系列其他章节,所有概念都在本章内闭环。
读完本章,你应当能够:(1) 画出从 getBean("userService") 到 UserService 对象被放进一级缓存的完整调用栈;(2) 解释三级缓存每一级的字段类型、存放内容、谁在什么时机写入与移除;(3) 说清楚为什么构造器循环依赖无解、而 setter 循环依赖可以被三级缓存化解;(4) 定位 @PostConstruct、InitializingBean.afterPropertiesSet、自定义 init-method 三者的先后顺序;(5) 在 7.0.9 的源码里指出单例创建锁从 synchronized 改为 ReentrantLock(singletonLock)后并发行为发生了什么变化。
需要特别提醒:本章所有源码片段均取自仓库 7.0.9 实际文件。网上大量 Spring 源码分析文章还停留在 5.x / 6.x,其中关于"单例锁是 synchronized (singletonObjects)"的描述在 7.0.9 已经不再成立------7.0.9 用的是 final Lock singletonLock = new ReentrantLock(),并且引入了 lenient creation(宽松创建)这套并发机制。本章会在第一次出现处显式标注这一差异。
2. 核心概念
在进入源码之前,必须先把几个容易混淆的抽象钉死。它们不是名词解释,而是后面读源码时会反复出现的"角色"。
2.1 BeanDefinition:Bean 的"配方",不是 Bean 本身
很多初学者把"注册了一个 Bean"理解成"容器里已经有了一个对象",这是错的。容器在启动阶段做的第一件事,是扫描类路径、解析注解、读取 XML,把每个 Bean 的"配方"写进 BeanDefinition 对象里------它记录了 Bean 的全限定类名、scope、是否懒加载、构造器参数、属性值、依赖关系、init-method / destroy-method、是否 primary、是否 lazyInit 等等。真正的对象要等到第一次被需要(或非懒加载单例在 refresh() 收尾时)才创建。
BeanDefinition 体系的根接口在 spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinition.java,而运行时真正被使用的是合并后的 RootBeanDefinition------父类 BeanDefinition 与子类 BeanDefinition 的属性在 getMergedLocalBeanDefinition 阶段被合并成一个 RootBeanDefinition,此后 createBean 拿到的永远是 RootBeanDefinition。本章源码中反复出现的 mbd 就是 merged Bean Definition 的缩写。
记住一句话:BeanDefinition 是配方,Object 是按配方煎好的饼;BeanFactory 是煎饼的后厨。
2.2 scope:Bean 的"生命周期作用域"
RootBeanDefinition 上有一个 scope 字段,默认值是 ConfigurableBeanFactory.SCOPE_SINGLETON(字符串 "singleton")。常见取值:
singleton:整个容器一份,存入三级缓存体系,容器关闭时统一销毁。prototype:每次getBean都新建一份,容器不持有它的引用、也不负责它的销毁(销毁回调只在创建瞬间登记一次,之后对象脱离容器管辖)。- 自定义 scope:由用户实现
org.springframework.beans.factory.config.Scope接口并通过ConfigurableBeanFactory#registerScope注册。Web 环境常见的request/session就是这种。
doGetBean 中三分支 mbd.isSingleton() / mbd.isPrototype() / else 就是按 scope 分发的,后文会逐行读。
2.3 FactoryBean 与普通 Bean 的区别:& 前缀
FactoryBean 是一个特殊接口(spring-beans/src/main/java/org/springframework/beans/factory/FactoryBean.java),实现它的 Bean 自己也是一个 Bean,但它生产出来的东西 又是另一个 Bean。当用户调用 getBean("xxx") 时,容器默认返回的是 FactoryBean.getObject() 的产物,而不是 FactoryBean 自己;要拿到 FactoryBean 本身,必须加 & 前缀,即 getBean("&xxx")。
这个 & 字符定义在 BeanFactory.FACTORY_BEAN_PREFIX_CHAR(即 '&')。AbstractBeanFactory.transformedBeanName 会先把它剥掉,再做别名解析;而 getObjectForBeanInstance 会根据调用者是否带 & 来决定返回 FactoryBean 自己还是它生产的对象。这是本章第一个必须吃透的"名字解析"细节。
2.4 BeanPostProcessor:Bean 生命周期的"插桩点"
BeanPostProcessor(spring-beans/.../factory/config/BeanPostProcessor.java)只有两个方法:postProcessBeforeInitialization 与 postProcessAfterInitialization。它的特殊性在于:它作用于每一个被创建的 Bean ,而不是某一个。AutowiredAnnotationBeanPostProcessor(处理 @Autowired)、CommonAnnotationBeanPostProcessor(处理 @Resource)、InitDestroyAnnotationBeanPostProcessor(处理 @PostConstruct / @PreDestroy)、ApplicationContextAwareProcessor(处理 ApplicationContextAware)全部以 BeanPostProcessor 的身份插进生命周期。
InstantiationAwareBeanPostProcessor 继承自 BeanPostProcessor,额外加了 postProcessBeforeInstantiation(实例化前短路)、postProcessAfterInstantiation(实例化后、属性填充前)、postProcessProperties(属性填充,替代已废弃的 postProcessPropertyValues)三个回调。SmartInstantiationAwareBeanPostProcessor 又加了 determineCandidateConstructors(推断构造器)与 getEarlyBeanReference(循环依赖时暴露早期引用)。这三层接口的关系是本章理解 populateBean 与循环依赖的钥匙。
2.5 Aware 接口:让 Bean 反向感知容器
Aware 是一个标记接口(spring-beans/.../factory/Aware.java)。它的子接口各有各的含义:BeanNameAware 让 Bean 知道自己在容器中的名字;BeanClassLoaderAware 拿到类加载器;BeanFactoryAware 拿到 BeanFactory 自身;ApplicationContextAware(在 spring-context)拿到 ApplicationContext。注意一个重要事实:BeanNameAware / BeanClassLoaderAware / BeanFactoryAware 这三个由 AbstractAutowireCapableBeanFactory.invokeAwareMethods 内联直接调用,不经过 BeanPostProcessor;而 ApplicationContextAware、EnvironmentAware 等"上下文级"Aware 则由 ApplicationContextAwareProcessor 在 postProcessBeforeInitialization 阶段回调。 这个时序差异在本章第 5 节会再次强调。
2.6 三级缓存:循环依赖的"缓冲带"
DefaultSingletonBeanRegistry 维护三个 Map:singletonObjects(成品单例)、earlySingletonObjects(半成品单例,已提前暴露)、singletonFactories(ObjectFactory,用于必要时才生成早期引用)。本章第 6、7 节会把这三个字段的类型、写入时机、读取路径全部画成状态机。读者先记住:三级缓存不是三个"缓存层级"那么简单,它是一套"把对象的构造时机与引用暴露时机解耦"的机制,核心目的是支持 setter 字段级别的循环依赖,同时把 AOP 代理的生成推迟到真正需要时。
3. 源码剖析(一):doGetBean ------ 拿 Bean 的总入口
3.1 从 getBean 到 doGetBean
用户调用的 beanFactory.getBean("userService") 最终走到 AbstractBeanFactory.doGetBean。它的方法签名是:
java
// spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java 第 235-238 行
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object @Nullable [] args, boolean typeCheckOnly)
throws BeansException {
四个参数:name 是用户给的名字(可能带 &、可能是别名);requiredType 是期望类型(用于最后做类型转换);args 是显式构造器参数(只在编程式 getBean(name, args) 时非空,且通常只对 prototype 有意义);typeCheckOnly 表示"这次拿 Bean 只是为了类型检查,不是真的要用"------为 true 时不会真正触发提前实例化。
下面把整个方法拆成七段逐行讲。
3.2 第一段:名字规范化 transformedBeanName
java
// AbstractBeanFactory.java 第 240-256 行
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, requiredType, name, beanName, null);
}
transformedBeanName 的实现只有一行(第 1271-1273 行):
java
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
它做两件事:(1) BeanFactoryUtils.transformedBeanName(name) 剥掉开头的 & 前缀(可能连续多个 &,见 BeanFactoryUtils.java 第 86-96 行的 while 循环);(2) canonicalName 沿别名链一直解析到最终的规范名字(别名表本身就是一个 Map<String,String>,解析循环直到 key 不再出现在别名表中)。这一步非常便宜------别名解析是纯内存 Map 查找,BeanFactoryUtils.transformedBeanName 还用了一个 transformedBeanNameCache(ConcurrentHashMap)缓存剥 & 的结果。
紧接着的 getSingleton(beanName) 调用的是 DefaultSingletonBeanRegistry 的无参重载(第 196-198 行),它内部就是 getSingleton(beanName, true)------先查一级缓存,再在循环依赖场景下查二、三级。这一步是"快速路径":绝大多数已经初始化完毕的单例在这里直接命中,后面所有分支都不走。
注意命中条件里的 args == null:如果用户带了显式构造器参数来 getBean,说明他想要的是一个"按这套参数现造的"Bean,绝不能直接返回缓存里那份不带这套参数的老对象。所以即使 sharedInstance != null,只要 args != null,也要走后面的创建分支。
命中后调用 getObjectForBeanInstance(...) 把"原始 sharedInstance"翻译成"用户真正想要的东西"------如果它是 FactoryBean 且用户没带 &,这里会去调用 FactoryBean.getObject() 拿产物;如果用户带了 &,则直接返回 FactoryBean 自己。这个方法第 3.6 节单独讲。
3.3 第二段:prototype 正在创建中的快速失败 + parent 回退
java
// AbstractBeanFactory.java 第 258-284 行
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory abf) {
return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
第一段的 else 表示"一级缓存没命中、需要走创建流程"。这里先做两个判断:
-
prototype 循环依赖直接报错 。
isPrototypeCurrentlyInCreation检查一个ThreadLocal<Set<String>>(prototypesCurrentlyInCreation),如果当前线程正在创建这个 prototype,说明两个 prototype 在构造器或 setter 里互相getBean了------prototype 没有缓存,无法提前暴露,只能直接抛BeanCurrentlyInCreationException。这就是"prototype 循环依赖无解"的源码根据。 -
parent BeanFactory 回退 。如果当前工厂里根本没有这个 Bean 的
BeanDefinition(containsBeanDefinition返回 false),但存在父工厂,就把请求原样转发给父工厂。注意转发时用的是originalBeanName(name)而不是beanName------originalBeanName(第 1280-1286 行)会把开头的&前缀补回去,保证父工厂拿到的是用户原始写的那个名字。
java
protected String originalBeanName(String name) {
String beanName = transformedBeanName(name);
if (!name.isEmpty() && name.charAt(0) == BeanFactory.FACTORY_BEAN_PREFIX_CHAR) {
beanName = FACTORY_BEAN_PREFIX + beanName;
}
return beanName;
}
这段代码解释了一个常被忽视的细节:父子容器的 Bean 名字是隔离的 。子容器优先,找不到才去父容器。这也是为什么在 Spring MVC 中,DispatcherServlet 的 WebApplicationContext 可以"看到"根容器 ContextLoaderListener 注册的 Bean(如 Service),但反过来不行。
3.4 第三段:typeCheckOnly 与合并 BeanDefinition
java
// AbstractBeanFactory.java 第 286-297 行
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
typeCheckOnly == true 的典型场景是 isTypeMatch / getType 这类"只想知道类型、不想真的造对象"的调用。此时不调用 markBeanAsCreated,意味着即使 BeanDefinition 是 abstract 的也不会因"标记为已创建"而报错;同时后面的 getMergedLocalBeanDefinition 拿到的 RootBeanDefinition 在 finally 里会被 clearMergedBeanDefinition 清掉(除非 isCacheBeanMetadata() 为 true),避免类型检查把 BeanDefinition 缓存住。
getMergedLocalBeanDefinition 做的事情前面提过:把父 BeanDefinition(parentName)与本 BeanDefinition 的属性合并,产出一个 RootBeanDefinition。如果合并过程中发现这个 mbd 是 abstract 的,或者带了显式 args 但 mbd 不是 prototype,checkMergedBeanDefinition 会立刻抛异常。
StartupStep 是 Spring 5.3 引入的可观测性钩子(ApplicationStartup),用于记录 Bean 创建耗时,默认实现是空的,不影响功能。
3.5 第四段:dependsOn 处理
java
// AbstractBeanFactory.java 第 299-327 行
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
......
}
}
@DependsOn 或 XML 的 depends-on 声明的是一种"我必须在它之后初始化、它必须在我之前销毁"的硬顺序。这里做三件事:
isDependent(beanName, dep)递归检查dependentBeanMap,看dep是否已经反向依赖了beanName(传递依赖也要查),是则抛Circular depends-on relationship。注意:@DependsOn形成的循环是直接报错的,不走三级缓存那套宽容逻辑------因为它表达的是纯粹的初始化顺序,不是字段注入。registerDependentBean(dep, beanName)在dependentBeanMap里登记"beanName 依赖 dep",这个映射在销毁阶段逆序销毁时要用。getBean(dep)立刻把依赖的 Bean 造出来。这意味着@DependsOn是一种" eager 触发",与字段注入那种"在 populateBean 阶段才触发"不同。
3.6 第五段:三分支------singleton / prototype / 自定义 scope
java
// AbstractBeanFactory.java 第 329-383 行
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
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.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, requiredType, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, requiredType, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, requiredType, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
三个分支的本质区别:
- singleton 分支 :把
createBean包成一个ObjectFactorylambda 传给getSingleton(beanName, singletonFactory)。这个getSingleton(DefaultSingletonBeanRegistry第 255-432 行)负责加锁、beforeSingletonCreation、调用 lambda、addSingleton入一级缓存、afterSingletonCreation。createBean 本身不在锁内完成 ------这是 7.0.9 并发模型的关键,第 6 节详述。注意 catch 块里的destroySingleton(beanName):创建失败时要把"为了解决循环依赖而提前暴露在二、三级缓存里的半成品"清理掉,否则下次别人getBean会拿到一个坏掉的引用。 - prototype 分支 :用
beforePrototypeCreation/afterPrototypeCreation在 ThreadLocal 里打个标记(防止 prototype 循环依赖无限递归),然后直接createBean,不进任何缓存。每次getBean都走一遍完整的createBean → doCreateBean。 - 自定义 scope 分支 :从
this.scopes这个Map<String, Scope>里按名字取出Scope实现,调用scope.get(beanName, objectFactory)。Scope.get的语义是"如果该 scope 上下文中已有这个 Bean 就返回旧的,否则用objectFactory现造一个并缓存"。RequestScope/SessionScope就是这么实现的。如果当前线程根本没有处于那个 scope 的上下文里(例如在一个非 Web 线程里访问requestscope 的 Bean),scope.get抛IllegalStateException,被包装成ScopeNotActiveException。
三个分支最后都过一道 getObjectForBeanInstance,统一处理 FactoryBean。
3.7 getObjectForBeanInstance:FactoryBean 的后处理
doGetBean 三个分支最后都调用同一个方法 getObjectForBeanInstance(AbstractBeanFactory.java 第 1841-1882 行):
java
protected Object getObjectForBeanInstance(Object beanInstance, @Nullable Class<?> requiredType,
String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factoryBean, requiredType, beanName, !synthetic);
}
return object;
}
逐段解读:
- 调用者带了
&前缀 (isFactoryDereference(name)为 true):他明确要的是 FactoryBean 自己。如果拿到的实例连FactoryBean都不是,抛BeanIsNotAFactoryException;否则直接返回 FactoryBean 实例本身。这就是getBean("&xxx")的全部秘密------transformedBeanName已经把&剥掉去查缓存了,但name这个原始参数还留着&,本方法靠它判断"要不要脱壳"。 - 调用者没带
&,且实例不是 FactoryBean:普通 Bean,直接返回。 - 实例是 FactoryBean,且调用者没带
&:要脱壳,返回FactoryBean.getObject()的产物。这里有个缓存细节------如果mbd == null(说明这个 sharedInstance 是通过手动registerSingleton注册的,没有 BeanDefinition),先从factoryBeanObjectCache里查 FactoryBean 已经生产过的对象;缓存没有才真正调用getObjectFromFactoryBean。getObjectFromFactoryBean内部对单例 FactoryBean 的产物会做缓存(这就是为什么同一个 FactoryBean 在 singleton 模式下多次getBean返回同一个对象),对 prototype FactoryBean 则每次都调getObject()。 synthetic标志位:Spring 内部合成的 Bean(如 AOP 框架自己造的 advisor)不需要再走一遍postProcessAfterInitialization,避免重复代理。
理解了这个方法,就能解释一个经典面试题:"为什么 getBean("&myFactoryBean") 拿到的是 FactoryBean,而 getBean("myFactoryBean") 拿到的是它生产的对象?"答案就在这 40 行代码里。
3.8 doGetBean 的收尾:类型自适应
java
// AbstractBeanFactory.java 第 399-422 行
return adaptBeanInstance(name, beanInstance, requiredType);
doGetBean 最后一步是 adaptBeanInstance。如果用户调用的是 getBean("xxx", SomeType.class),而实际拿到的 Bean 不是 SomeType 的实例,就尝试用 TypeConverter 做一次转换(典型场景:Bean 是 String,用户要的是 Integer)。转换失败抛 BeanNotOfRequiredTypeException。
至此,doGetBean 的全部逻辑讲完。它的职责其实非常清晰:名字解析 → 查缓存 → 失败则按 scope 分发创建 → FactoryBean 脱壳 → 类型适配 。真正的"造对象"工作被委托给了抽象方法 createBean,其实现是 AbstractAutowireCapableBeanFactory.createBean。
4. 源码剖析(二):createBean 与 doCreateBean
4.1 createBean:实例化前的"短路"机会
AbstractAutowireCapableBeanFactory.createBean(第 487-540 行)是真正开始造对象的地方:
java
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object @Nullable [] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point...
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
......
return beanInstance;
}
......
}
这段做了四件事:
- 解析 Bean Class 。
resolveBeanClass把 mbd 里存的类名字符串真正解析成Class对象(涉及类加载)。如果 mbd 之前只有类名没有 Class(动态代理场景常见),这里会 clone 一份 mbd 出来(new RootBeanDefinition(mbd)),把 Class 设进去------为什么要 clone?因为合并后的 mbd 是多个 Bean 共享的,不能直接改它的 beanClass 字段 ,否则并发下会串味。prepareMethodOverrides则是校验lookup-method/replaced-method这些方法覆写配置。 - resolveBeforeInstantiation 短路 。这是给
InstantiationAwareBeanPostProcessor的一次"插队"机会:如果某个 BPP 返回了一个非 null 对象,整个doCreateBean就被跳过,直接返回这个对象。AOP 的AbstractAutoProxyCreator就利用这个短路路径------但要注意,它大多数时候返回 null(只在特殊场景才提前代理),真正的 AOP 代理是在postProcessAfterInitialization阶段做的。 - 正常路径调 doCreateBean。
- 异常包装 。
BeanCreationException直接往上抛,其他 Throwable 包装成BeanCreationException。
4.2 resolveBeforeInstantiation:短路路径的完整逻辑
java
// AbstractAutowireCapableBeanFactory.java 第 1124-1140 行
protected @Nullable Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
注意一个关键细节:短路路径一旦命中,会立刻把 postProcessAfterInitialization 也跑一遍 (第 1133 行)。这是因为短路返回的对象跳过了正常的 doCreateBean,而 doCreateBean 末尾本来会调 initializeBean,里面就包含 applyBeanPostProcessorsAfterInitialization。为了让短路对象也享受到同样的后处理,这里手动补一次。mbd.beforeInstantiationResolved 是一个缓存标志------一旦这个 mbd 已经走过短路判断(无论成功失败),下次创建时就不再重复判断,避免对同一个 mbd 反复执行 BPP。
applyBeanPostProcessorsBeforeInstantiation(第 1153-1161 行)遍历所有 InstantiationAwareBeanPostProcessor,谁先返回非 null 就用谁:
java
protected @Nullable Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
return null;
}
这里用的是 getBeanPostProcessorCache().instantiationAware 而不是直接遍历 getBeanPostProcessors()------7.0.9 对 BPP 列表做了分类缓存(按 InstantiationAware / SmartInstantiationAware / DestructionAware 等接口分组),避免每次都 instanceof 判断。这是一个性能优化点。
4.3 doCreateBean:真正的创建流程
doCreateBean(第 556-649 行)是本章最核心的方法,没有之一。它一共做六件事:实例化 → 合并 BPP 后处理 → 提前暴露早期引用 → 属性填充 → 初始化 → 注册销毁回调。我们逐段读。
java
// AbstractAutowireCapableBeanFactory.java 第 559-571 行
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
第一行 factoryBeanInstanceCache.remove(beanName) 是一个性能优化:在 getTypeForFactoryBean 等"只拿类型不真创建"的场景下,Spring 可能已经提前把 FactoryBean 实例造好了缓存在这个 cache 里;如果是,直接取出来用,避免重复创建。普通 Bean 这里 cache 是空的,必然走 createBeanInstance。
实例化完成后拿到的是一个 BeanWrapper------它包装着刚 new 出来、但属性还没填的裸对象。beanType 记录解析出来的目标类型,写回 mbd 的 resolvedTargetType 字段,供后续类型推断使用。
java
// 第 573-585 行
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.markAsPostProcessed();
}
}
这一步是给 MergedBeanDefinitionPostProcessor 的回调时机。AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(第 279 行)在这里扫描出所有 @Autowired / @Value 注解的字段和方法,缓存成 InjectionMetadata。**为什么要在实例化后、属性填充前做这件事?**因为扫描需要知道真实的 beanClass(被 CGLIB 代理过的类要拿到用户类),而且扫描结果要在 populateBean 的 postProcessProperties 阶段直接拿来用。synchronized (mbd.postProcessingLock) + mbd.postProcessed 标志保证这个扫描对每个 mbd 只做一次。
java
// 第 587-597 行
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
这是三级缓存写入的唯一点。 三个条件同时满足才注册:(1) 是 singleton;(2) 全局开关 allowCircularReferences 为 true(默认 true,可通过 setAllowCircularReferences(false) 关闭);(3) isSingletonCurrentlyInCreation(beanName) 返回 true------说明当前线程正在 beforeSingletonCreation 之后、afterSingletonCreation 之前,也就是在 getSingleton(beanName, ObjectFactory) 的 lambda 里执行 createBean 的过程中。
注册的内容不是对象本身,而是一个 lambda:() -> getEarlyBeanReference(beanName, mbd, bean)。这个 lambda 闭包捕获了刚 new 出来的裸 bean。它什么时候被调用?只有在循环依赖真的发生、另一个 Bean 在 populateBean 时来 getBean(beanName)、并且一级、二级缓存都没命中时,才会执行这个 lambda。getEarlyBeanReference(第 966-974 行)遍历所有 SmartInstantiationAwareBeanPostProcessor,让它们有机会把裸 bean 包装成早期引用(通常是 AOP 代理):
java
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
这就是"为什么需要三级缓存而不是两级"的核心:把"是否要为这个 Bean 生成 AOP 代理"的决策推迟到真正发生循环依赖时 。如果没有循环依赖,这个 lambda 永远不会被调用,getEarlyBeanReference 也不会被执行,AOP 代理会等到 postProcessAfterInitialization 阶段才生成------这是正常路径。如果有循环依赖,lambda 被调用,AOP 必须在此时就把代理造出来,否则循环的另一方拿到的就是裸对象,而最终成品却是代理,两边引用不一致。
java
// 第 599-610 行
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
throw bce;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
}
属性填充与初始化,两个方法后面专门讲。注意 exposedObject 初值是裸 bean,但 initializeBean 可能返回一个被 BPP 包装过的代理对象------所以 exposedObject 可能与 bean 不再是同一个引用。
java
// 第 612-637 行
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = CollectionUtils.newLinkedHashSet(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. ...");
}
}
}
}
这段是循环依赖收尾时的"引用一致性校验",非常精妙:
getSingleton(beanName, false)注意第二个参数是 false------不允许再生成新的早期引用,只查已有缓存。如果返回非 null,说明在 populateBean 阶段,已经有别的 Bean 通过三级缓存把我们的 lambda 消费掉了,早期引用已经登记在二级缓存里。- 如果
exposedObject == bean(说明initializeBean没有把 bean 包装成代理),那最终暴露的对象就用earlySingletonReference------虽然它和bean在这个场景下是同一个东西,但从缓存里取能保证引用一致。 - 如果
exposedObject != bean(说明initializeBean把 bean 包装成了代理),但别的 Bean 已经拿到了我们的裸对象作为早期引用------这就出问题了:别人手里是裸对象,我们最终放进容器的是代理,类型都不对 。此时 Spring 会检查allowRawInjectionDespiteWrapping(默认 false),如果不允许"原始注入",就抛BeanCurrentlyInCreationException,错误信息提示"考虑用 getBeanNamesForType 并关闭 allowEagerInit"。这个异常在实际开发中偶尔会遇到,通常是@Async/@Transactional与循环依赖同时出现导致的。
java
// 第 639-648 行
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
最后一步注册销毁回调(只对 singleton 与自定义 scope 生效,prototype 不注册)。返回 exposedObject------这可能是裸对象,也可能是代理。
4.4 createBeanInstance:四种实例化方式
createBeanInstance(第 1175-1230 行)决定"到底用哪种方式 new 这个对象":
java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object @Nullable [] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
if (args == null) {
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName, mbd);
}
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
按优先级排列四条路径:
- Supplier 回调 。
mbd.getInstanceSupplier()非空时,直接调用supplier.get()拿对象。这是编程式注册 BeanDefinition 时最灵活的方式------用户自己控制怎么 new。 - 工厂方法 。
mbd.getFactoryMethodName()非空(XML 里的factory-method或@Bean方法),走instantiateUsingFactoryMethod,由ConstructorResolver解析工厂方法并推断参数。@Bean方法最终就是走这条路------Spring 容器调用配置类里的@Bean方法来产生对象。 - 构造器自动注入 。触发条件有四个,任一满足即走
autowireConstructor:determineConstructorsFromBeanPostProcessors返回了非空构造器数组(典型:类里有一个构造器标了@Autowired,或者 Kotlin 类的主构造器);- mbd 的 autowireMode 是
AUTOWIRE_CONSTRUCTOR; - 显式声明了构造器参数值;
- 用户带了显式 args。 这条路是最复杂的:
ConstructorResolver.autowireConstructor会做构造器候选筛选、参数类型匹配、参数值自动解析(把RuntimeBeanReference解析成getBean结果),最后反射调用。
- 默认无参构造 。前面都不命中,走
instantiateBean,用CglibSubclassingInstantiationStrategy(默认实例化策略,第 178 行this.instantiationStrategy = new CglibSubclassingInstantiationStrategy())反射调用无参构造器。注意:如果类里没有无参构造器且没走自动注入分支,这里会抛NoSuchMethodException。
determineConstructorsFromBeanPostProcessors(第 1314-1326 行)把构造器推断权交给 SmartInstantiationAwareBeanPostProcessor,具体实现就是 AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(第 349-452 行)。它的核心逻辑是:扫描所有声明的构造器,找出标了 @Autowired 的;如果有一个标了 @Autowired(required=true),它就是唯一候选;如果有多个标了 @Autowired(required=false),再加上无参构造器作为 fallback;如果类里根本没有 @Autowired 构造器但只有一个带参构造器,Spring 6+ 会把它作为隐式候选(第 434-436 行)------这就是为什么一个类只写了一个带参构造器、不加 @Autowired 也能被自动注入。
5. 源码剖析(三):populateBean 属性填充
5.1 populateBean 主流程
populateBean(第 1390-1461 行)负责把 BeanDefinition 里声明的属性值、以及 @Autowired / @Resource 注解的依赖,真正塞进刚 new 出来的对象里。完整源码:
java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
if (bw.getWrappedClass().isRecord()) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
}
else {
// Skip property population phase for records since they are immutable.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
if (hasInstantiationAwareBeanPostProcessors()) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
pvs = pvsToUse;
}
}
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
按执行顺序拆成五段:
第 1 段:null / record 快速跳过 。如果实例化出来的是 NullBean(Supplier 返回 null 时的占位)或者根本没有 PropertyValues,直接返回。Java record 是不可变的(没有 setter),也不允许属性填充------但如果 record 通过构造器注入了依赖,构造器那一关在 createBeanInstance 已经完成了,这里跳过不影响。
第 2 段:postProcessAfterInstantiation 回调 。这是 InstantiationAwareBeanPostProcessor 的第二个回调,时机在"实例化完成、属性填充之前"。任何一个 BPP 返回 false,整个 populateBean 立刻 return------连 @Autowired 都不会执行。这个回调用得很少,但 Spring Boot 的某些配置处理器会用它。
第 3 段:传统 autowire byName / byType 。这是 XML 时代 <bean autowire="byType"> 的逻辑,注解驱动开发几乎用不到。autowireByName(第 1472-1493 行)扫描所有"有 setter 但还没赋值的非简单属性",按属性名去容器里 getBean(propertyName);autowireByType(第 1506-1544 行)则按属性类型走 resolveDependency。
第 4 段:postProcessProperties 回调------@Autowired / @Resource 真正发生的地方 。这是现代 Spring 最关键的一步。AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java 第 490-502 行):
java
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
findAutowiringMetadata 在第 527-544 行,它从缓存里取(或新建)一个 InjectionMetadata------这个对象在 doCreateBean 的 applyMergedBeanDefinitionPostProcessors 阶段就已经扫描好并缓存了,里面是一个 InjectedElement 列表,每个元素对应一个 @Autowired 字段或方法。metadata.inject(bean, beanName, pvs) 遍历这些元素,对每个元素调用 resolveDependency 拿到依赖对象,再反射赋值(字段直接 field.set,方法 method.invoke)。
第 5 段:applyPropertyValues 。把 mbd 里显式声明的 PropertyValues(XML 的 <property> 或 @Bean 方法里的 BeanDefinitionBuilder.addPropertyValue)真正写到 Bean 上。注解驱动的 @Autowired 在这里已经完成了,本步主要处理 XML / 编程式配置的属性。
5.2 applyPropertyValues:RuntimeBeanReference 的解析
applyPropertyValues(第 1660-1747 行)做的事情可以概括为"遍历 PropertyValue 列表,把每个值从'声明时的占位对象'解析成'运行时真正的对象',再写进 BeanWrapper"。关键片段:
java
// AbstractAutowireCapableBeanFactory.java 第 1687-1735 行
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = isConvertibleProperty(propertyName, bw);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue typedStringValue &&
!typedStringValue.isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
这里出现了几个关键角色:
BeanDefinitionValueResolver(spring-beans/.../factory/support/BeanDefinitionValueResolver.java):它的resolveValueIfNecessary是一个"类型分发器"------如果值是RuntimeBeanReference(XML 里的<ref bean="xxx">),就getBean(((RuntimeBeanReference) value).getBeanName());如果是TypedStringValue(字面量字符串),就用 TypeConverter 转成目标类型;如果是RuntimeBeanNameReference,就返回 Bean 名字字符串本身;如果是BeanDefinition(内嵌 bean),就现场createBean。循环依赖在这里通过getBean重新进入doGetBean,从而触发三级缓存查找。AutowiredPropertyMarker.INSTANCE:这是一个特殊标记对象,当 autowire byType 解析出某个属性需要自动注入时,会把这个标记塞进 PropertyValue;这里再把它还原成一个DependencyDescriptor,交给valueResolver走标准依赖解析流程。- 类型转换与缓存 :
convertForProperty用TypeConverterDelegate(底层是PropertyEditor或ConversionService)把字符串转成数字、日期等。转换结果会被pv.setConvertedValue(convertedValue)缓存------下一次创建同一个 mbd 的 Bean 时,pv.isConverted()直接为 true,跳过解析,这是 prototype Bean 重复创建时的性能优化。 bw.setPropertyValues(...):最后调用BeanWrapperImpl.setPropertyValues,它内部对每个属性找到对应的 setter(或字段),反射赋值。嵌套属性(person.name)、索引属性(list[0])、Map 属性(map['key'])都在这里支持。
5.3 resolveDependency:按类型找 Bean 的决策中心
@Autowired 字段在 metadata.inject 阶段,最终会调到 DefaultListableBeanFactory.resolveDependency(第 1636-1659 行):
java
@Override
public @Nullable Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (jakartaInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else if (descriptor.supportsLazyResolution()) {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result != null) {
return result;
}
}
return doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
这个方法处理了五种"特殊依赖类型",优先级从高到低:
Optional<T>:包成Optional返回。createOptionalDependency(第 2340 行)内部还是调doResolveDependency,找不到就返回Optional.empty(),不报错。ObjectFactory<T>/ObjectProvider<T>:不真正解析依赖,返回一个DependencyObjectProvider(第 2507 行开始的内部类)。这个对象是一个惰性工厂------调用getObject()/getIfAvailable()时才真正去容器里找 Bean。这就是为什么可以写@Autowired ObjectProvider<UserService> userProvider,它不会在启动时触发 UserService 的创建。- JSR-330 的
Provider<T>:同上,包一层Jsr330Factory的适配器。 @Lazy注解 :descriptor.supportsLazyResolution()为 true 时,调getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary。在 Spring 应用里,这个 resolver 实际是ContextAnnotationAutowireCandidateResolver,它返回一个 AOP 代理------真正的 Bean 在代理方法被第一次调用时才解析。这个机制第 7 节单独讲。- 普通依赖 :走
doResolveDependency。
doResolveDependency(第 1662 行起)是真正的"按类型找 Bean"算法,分四步:
java
// DefaultListableBeanFactory.java 第 1667-1735 行(节选关键步骤)
// Step 1: pre-resolved shortcut for single bean match
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
// Step 2: @Value 的值或表达式
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String strValue) {
String resolvedValue = resolveEmbeddedValue(strValue);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(resolvedValue, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
// Step 3: 按字段名 / @Qualifier 指定的名字直接定位
if (descriptor.usesStandardBeanLookup()) {
String dependencyName = descriptor.getDependencyName();
if (dependencyName == null || !containsBean(dependencyName)) {
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
dependencyName = (suggestedName != null && containsBean(suggestedName) ? suggestedName : null);
}
if (dependencyName != null) {
dependencyName = canonicalName(dependencyName);
if (isTypeMatch(dependencyName, type) && isAutowireCandidate(dependencyName, descriptor) &&
!isFallback(dependencyName) && !hasPrimaryConflict(dependencyName, type) &&
!isSelfReference(beanName, dependencyName)) {
if (autowiredBeanNames != null) {
autowiredBeanNames.add(dependencyName);
}
Object dependencyBean = resolveBean(dependencyName, descriptor.getResolvableType());
return resolveInstance(dependencyBean, descriptor, type, dependencyName);
}
}
}
// Step 4a: 集合 / 数组 / Map 多 Bean 注入
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// Step 4b: 按类型找所有候选,再选唯一 / primary / @Priority
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// Step 4c: 自定义 Collection / Map 兜底
multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
这四步解释了几乎所有 @Autowired 行为:
- Step 2 :
@Value("${...}")的值在这里被解析、占位符替换、SpEL 求值、类型转换。 - Step 3 :
@Autowired UserService userService这种字段名与 Bean 名一致的情况,直接按名字定位,避免类型匹配的开销。@Qualifier("xxx")指定的名字也走这里(getSuggestedName)。 - Step 4a :
@Autowired List<UserService>、@Autowired Map<String, UserService>、@Autowired UserService[]、@Autowired Stream<UserService>都在这里被识别为"多 Bean 注入",容器把所有同类型 Bean 收集成集合返回。resolveMultipleBeans(第 1793 行)对 Stream 类型有特殊处理------返回的是一个Stream,元素是按需解析的,而不是一次性全收集。 - Step 4b :单个依赖、按类型匹配。
findAutowireCandidates返回所有类型兼容的 Bean;如果只有一个,直接用;如果有多个,挑@Primary的;还挑不出来,再按字段名与 Bean 名匹配;再不行抛NoUniqueBeanDefinitionException。
5.4 required 语义
isRequired(descriptor) 判断这个注入点是否"必须满足"。@Autowired(required = false) 的字段如果找不到 Bean,Spring 不会报错,只是把字段留空(或保持 null);required = true(默认)则抛 NoSuchBeanDefinitionException。注意一个细节:@Autowired(required = false) 的字段如果恰好与某个 Bean 循环依赖,它不会触发三级缓存的提前暴露逻辑------因为它不是"硬依赖",容器允许它为 null。这在排查循环依赖问题时是一个有用的逃生口。
@Resource 的处理由 CommonAnnotationBeanPostProcessor(spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java)完成。它也实现了 postProcessProperties,但解析顺序与 @Autowired 不同:先按名字找(@Resource(name="xxx") 或字段名),找不到再按类型找。它还负责 @PostConstruct / @PreDestroy 吗?不------这两个注解由它的父类 InitDestroyAnnotationBeanPostProcessor(spring-context/.../annotation/InitDestroyAnnotationBeanPostProcessor.java)处理,CommonAnnotationBeanPostProcessor 只是在构造器里把 javax.annotation.PostConstruct / javax.annotation.PreDestroy(7.0.9 已经是 jakarta.annotation)注册给父类。
6. 源码剖析(四):initializeBean 初始化
属性填充完成后,Bean 已经是一个"数据完整但尚未经过初始化回调"的对象。initializeBean(第 1797-1822 行)负责走完最后一公里:
java
@SuppressWarnings("deprecation")
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// Skip initialization of a NullBean
if (bean.getClass() == NullBean.class) {
return bean;
}
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
四步,顺序固定,这就是 Bean 初始化的标准时序:
6.1 第一步:invokeAwareMethods(内联调用三个 Aware)
java
// AbstractAutowireCapableBeanFactory.java 第 1824-1839 行
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware beanNameAware) {
beanNameAware.setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
beanClassLoaderAware.setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware beanFactoryAware) {
beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
这三个 Aware 由容器内联直接调用,不经过任何 BPP。注意调用顺序是 BeanNameAware → BeanClassLoaderAware → BeanFactoryAware。
**为什么这三个要内联,而其他 Aware 走 BPP?**因为 BeanFactory 这个引用本身不能通过 BeanPostProcessor 来注入------BeanPostProcessor 自己也需要被容器创建,而创建 BPP 的过程中如果它要拿 BeanFactory,必须有一个"更早"的机制。所以最底层的三个 Aware 被硬编码在 initializeBean 开头。
而 ApplicationContextAware、EnvironmentAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware 这些"应用上下文级"Aware,则由 ApplicationContextAwareProcessor(spring-context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java 第 82-112 行)在下一步 postProcessBeforeInitialization 中回调:
java
@Override
public @Nullable Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Aware) {
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware environmentAware) {
environmentAware.setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware embeddedValueResolverAware) {
embeddedValueResolverAware.setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware resourceLoaderAware) {
resourceLoaderAware.setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware applicationEventPublisherAware) {
applicationEventPublisherAware.setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware messageSourceAware) {
messageSourceAware.setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationStartupAware applicationStartupAware) {
applicationStartupAware.setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware applicationContextAware) {
applicationContextAware.setApplicationContext(this.applicationContext);
}
}
时序结论 :BeanNameAware / BeanClassLoaderAware / BeanFactoryAware 先执行(内联),然后 postProcessBeforeInitialization 里 ApplicationContextAwareProcessor 再执行 EnvironmentAware / ResourceLoaderAware / ApplicationContextAware 等。这就是为什么在一个 Bean 里同时实现 BeanFactoryAware 和 ApplicationContextAware,前者先回调。
6.2 第二步:applyBeanPostProcessorsBeforeInitialization(@PostConstruct 在这里)
这一步遍历所有 BeanPostProcessor,调用它们的 postProcessBeforeInitialization。其中最重要的实现是 InitDestroyAnnotationBeanPostProcessor------它负责执行所有标了 @PostConstruct 的方法。
它的执行时机非常关键:在 invokeInitMethods(即 afterPropertiesSet)之前。这就决定了三者顺序:
kotlin
@PostConstruct 方法 → InitializingBean.afterPropertiesSet() → 自定义 init-method
这个顺序是面试高频题,源码根据就在这里:applyBeanPostProcessorsBeforeInitialization 在 invokeInitMethods 之前调用。
6.3 第三步:invokeInitMethods(InitializingBean + 自定义 init-method)
java
// AbstractAutowireCapableBeanFactory.java 第 1854-1877 行
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
((InitializingBean) bean).afterPropertiesSet();
}
if (mbd != null && bean.getClass() != NullBean.class) {
String[] initMethodNames = mbd.getInitMethodNames();
if (initMethodNames != null) {
for (String initMethodName : initMethodNames) {
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
}
}
}
}
}
逐行讲:
- 如果 Bean 实现了
InitializingBean接口,调afterPropertiesSet()。注意hasAnyExternallyManagedInitMethod("afterPropertiesSet")这个判断------如果用户在 mbd 里显式把afterPropertiesSet注册为"外部管理的 init-method"(比如通过@Bean(initMethod="afterPropertiesSet")),这里就跳过,避免重复调用。 - 然后遍历
mbd.getInitMethodNames()(7.0.9 支持多个 init-method,返回数组),逐个反射调用。invokeCustomInitMethod(第 1886 行)通过MethodDescriptor解析方法名(支持@Bean(initMethod="myInit")这种字符串配置),找不到时如果是"默认 init-method"(AbstractBeanDefinition.INFER_METHOD)则静默跳过,如果是用户显式指定的则抛异常。
6.4 第四步:applyBeanPostProcessorsAfterInitialization(AOP 代理在这里)
最后一步再遍历所有 BPP 的 postProcessAfterInitialization。这是 AOP 真正生成代理的地方 (AbstractAutoProxyCreator.postProcessAfterInitialization)。如果一个 Bean 需要被事务、缓存、Async 等切面增强,它在这里被替换成代理对象。
回到 doCreateBean 的那段引用一致性校验(第 4.3 节):如果这里把 bean 包装成了代理(exposedObject != bean),而循环依赖的另一方已经通过三级缓存拿到了裸对象,Spring 就会抛那个"raw version injected"异常。理解了这一步,就理解了为什么 @Transactional + 循环依赖这么容易出问题。
7. 源码剖析(五):单例创建状态机与三级缓存
7.1 DefaultSingletonBeanRegistry 的字段全景
DefaultSingletonBeanRegistry(spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java)是整个单例管理的核心。7.0.9 的字段区(第 82-137 行)与旧版本差异很大,必须完整读一遍:
java
// DefaultSingletonBeanRegistry.java 第 82-137 行
/** Common lock for singleton creation. */
final Lock singletonLock = new ReentrantLock();
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Creation-time registry of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(16);
/** Custom callbacks for singleton creation/registration. */
private final Map<String, Consumer<Object>> singletonCallbacks = new ConcurrentHashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = Collections.synchronizedSet(new LinkedHashSet<>(256));
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation = ConcurrentHashMap.newKeySet(16);
/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions = ConcurrentHashMap.newKeySet(16);
/** Specific lock for lenient creation tracking. */
private final Lock lenientCreationLock = new ReentrantLock();
/** Specific lock condition for lenient creation tracking. */
private final Condition lenientCreationFinished = this.lenientCreationLock.newCondition();
/** Names of beans that are currently in lenient creation. */
private final Set<String> singletonsInLenientCreation = new HashSet<>();
/** Map from one creation thread waiting on a lenient creation thread. */
private final Map<Thread, Thread> lenientWaitingThreads = new HashMap<>();
/** Map from bean name to actual creation thread for currently created beans. */
private final Map<String, Thread> currentCreationThreads = new ConcurrentHashMap<>();
/** Flag that indicates whether we're currently within destroySingletons. */
private volatile boolean singletonsCurrentlyInDestruction = false;
/** Disposable bean instances: bean name to disposable instance. */
private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();
/** Map between dependent bean names: bean name to Set of dependent bean names. */
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
/** Map between depending bean names: bean name to Set of bean's dependencies. */
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
把这些字段按职责分组:
三级缓存本体:
singletonObjects(一级):成品单例,ConcurrentHashMap,256 初始容量。earlySingletonObjects(二级):提前暴露的半成品,ConcurrentHashMap,16 初始容量。singletonFactories(三级):ObjectFactory,7.0.9 里它也已经是ConcurrentHashMap(注意:Spring 6.x 之前这里是HashMap,因为读写都在singletonLock保护下;7.0.9 把读路径改成了无锁快速路径,所以换成了并发 Map)。
创建状态跟踪:
singletonsCurrentlyInCreation:当前正在创建中的 Bean 名字集合(ConcurrentHashMap.newKeySet)。beforeSingletonCreation加入,afterSingletonCreation移除。inCreationCheckExclusions:豁免检查的 Bean 名字集合(某些手动注册或特殊场景跳过"正在创建"校验)。currentCreationThreads:beanName → 正在创建它的线程,7.0.9 新增,用于 lenient creation 场景下判断"谁在等谁"。
7.0.9 新增的 lenient creation(宽松创建)机制:
singletonLock:ReentrantLock,单例创建的主锁。lenientCreationLock+lenientCreationFinished:配套的锁与条件变量。singletonsInLenientCreation:正在"宽松创建"的 Bean 集合(注意它是普通HashSet,必须在lenientCreationLock下访问)。lenientWaitingThreads:线程等待关系图,用于检测宽松创建场景下的死锁。
销毁与依赖关系:
disposableBeans:需要销毁的 Bean(LinkedHashMap,保持注册顺序)。dependentBeanMap/dependenciesForBeanMap:双向依赖图,用于逆序销毁。singletonsCurrentlyInDestruction:volatile boolean,标记容器是否正在销毁阶段。
版本差异重点 :Spring 6.x 及更早,单例创建的锁是 synchronized (this.singletonObjects);7.0.9 改为 final Lock singletonLock = new ReentrantLock(),并且 getSingleton(String, boolean) 用 tryLock() 快速失败。这个变化的动机是:早期版本整个单例创建期间都持有全局锁,导致容器启动时即使有多个线程也只能串行造 Bean;7.0.9 允许"宽松创建"------某些场景下,Bean 创建可以不持有 singletonLock,从而提高并发启动性能。代价是引入了上面这一整套 lenientCreation* 字段来处理并发冲突。
7.2 getSingleton(String, boolean):三级缓存查找
这个方法在样式范例里已经完整贴过(第 208-244 行),这里从状态机角度再提炼一遍:
java
protected @Nullable Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock.
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
if (!this.singletonLock.tryLock()) {
// Avoid early singleton inference outside of original creation thread.
return null;
}
try {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
if (this.singletonFactories.remove(beanName) != null) {
this.earlySingletonObjects.put(beanName, singletonObject);
}
else {
singletonObject = this.singletonObjects.get(beanName);
}
}
}
}
}
finally {
this.singletonLock.unlock();
}
}
}
return singletonObject;
}
状态转移:
- 查一级 → 命中则返回(最快路径,无锁)。
- 一级未命中 + Bean 正在创建中 → 查二级。命中则返回。
- 二级未命中 + 允许早期引用 →
tryLock()。tryLock失败:说明当前 singletonLock 被原创建线程持有,我们不是原创建线程,直接返回 null ,不阻塞。这是 7.0.9 的关键变化------旧版本会阻塞在这里,可能导致跨线程循环依赖的死锁;新版本选择"放弃早期引用",让上层doGetBean走完整创建流程(虽然可能重复创建,但由getSingleton(String, ObjectFactory)的去重逻辑兜底)。tryLock成功:double-check 一、二级,都没有才从三级取出ObjectFactory调getObject(),把结果放进二级,并从三级移除。三级消费一次后即升级为二级 ,后续线程直接命中二级,不会重复执行getEarlyBeanReference。
7.3 getSingleton(String, ObjectFactory):单例创建的状态机
这是 doGetBean singleton 分支真正调用的方法(第 255-432 行)。它比 getSingleton(String, boolean) 复杂得多,因为它要处理"创建"本身。我们按阶段讲:
阶段 1:尝试拿锁
java
// 第 258-261 行
Thread currentThread = Thread.currentThread();
Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock();
boolean acquireLock = !Boolean.FALSE.equals(lockFlag);
boolean locked = (acquireLock && this.singletonLock.tryLock());
isCurrentThreadAllowedToHoldSingletonLock() 在基类返回 null(第 458-460 行),但 DefaultListableBeanFactory 重写了它------在容器预实例化阶段,主线程返回 true,后台线程返回 false。lockFlag 三态语义:
null:传统行为,必须拿全局锁。TRUE:当前线程允许持锁,但如果拿不到锁,可以走 lenient 路径宽松创建。FALSE:当前线程不允许持锁,必须走 lenient 路径。
阶段 2:拿不到锁时的 lenient 回退
java
// 第 266-298 行
if (acquireLock && !locked) {
if (Boolean.TRUE.equals(lockFlag)) {
// Another thread is busy in a singleton factory callback, potentially blocked.
// Fallback as of 6.2: process given singleton bean outside of singleton lock.
this.lenientCreationLock.lock();
try {
Set<String> lockedBeans = new HashSet<>(this.singletonsCurrentlyInCreation);
lockedBeans.removeAll(this.singletonsInLenientCreation);
logger.info("Obtaining singleton bean '" + beanName + "' in thread \"" +
currentThread.getName() + "\" while other thread holds singleton " +
"lock for other beans " + lockedBeans);
this.singletonsInLenientCreation.add(beanName);
}
finally {
this.lenientCreationLock.unlock();
}
}
else {
// No specific locking indication -> wait.
this.singletonLock.lock();
locked = true;
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject != null) {
return singletonObject;
}
}
}
如果主线程(lockFlag=TRUE)发现锁被别人占了,它不等待,而是把自己标记为"宽松创建"------在不持有 singletonLock 的情况下继续创建这个 Bean。这是 6.2 引入、7.0.9 继续强化的性能优化:容器启动时主线程负责按顺序创建单例,如果它创建到一半去 getBean 一个依赖,而这个依赖恰好被另一个后台线程锁住了,主线程不必阻塞,自己宽松地把依赖造出来 。lockFlag=FALSE 的线程(后台线程)则必须老老实实 lock() 等待。
阶段 3:销毁期检查 + beforeSingletonCreation
java
// 第 300-358 行
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
......
try {
beforeSingletonCreation(beanName);
}
catch (BeanCurrentlyInCreationException ex) {
// 宽松创建场景下的等待逻辑...
}
beforeSingletonCreation(第 539-543 行)把 beanName 加进 singletonsCurrentlyInCreation:
java
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
Set.add 返回 false 表示这个 beanName 已经在集合里了------说明当前线程(或另一个线程)正在创建它 。如果是当前线程导致的,那就是循环依赖信号;如果是另一个线程导致的,宽松创建场景下这里会进入 catch (BeanCurrentlyInCreationException ex) 块,在 lenientCreationLock 上 await() 等待对方创建完成(第 312-358 行)。这段等待逻辑配合 lenientWaitingThreads 做了环路检测------如果发现等待关系成环(A 等 B、B 等 A),就直接抛异常,不死等。
阶段 4:真正调用 createBean
java
// 第 365-400 行
try {
// Leniently created singleton object could have appeared in the meantime.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
this.currentCreationThreads.put(beanName, currentThread);
try {
singletonObject = singletonFactory.getObject();
}
finally {
this.currentCreationThreads.remove(beanName);
}
newSingleton = true;
}
}
......
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
singletonFactory.getObject() 就是 doGetBean 传进来的 lambda,里面调 createBean → doCreateBean。这一整段就是 Bean 的完整生命周期。afterSingletonCreation 把 beanName 从 singletonsCurrentlyInCreation 移除。
阶段 5:addSingleton 入一级缓存
java
// 第 402-413 行
if (newSingleton) {
try {
addSingleton(beanName, singletonObject);
}
catch (IllegalStateException ex) {
// Leniently accept same instance if implicitly appeared.
Object object = this.singletonObjects.get(beanName);
if (singletonObject != object) {
throw ex;
}
}
}
addSingleton(第 159-173 行)做四件事:写一级、删三级、删二级、加入注册顺序集合:
java
protected void addSingleton(String beanName, Object singletonObject) {
Object oldObject = this.singletonObjects.putIfAbsent(beanName, singletonObject);
if (oldObject != null) {
throw new IllegalStateException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
}
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
Consumer<Object> callback = this.singletonCallbacks.get(beanName);
if (callback != null) {
callback.accept(singletonObject);
}
}
注意 putIfAbsent------如果另一个线程已经抢先注册了同名 Bean,抛 IllegalStateException,外层 catch 里检查是不是同一个对象(宽松创建场景下两个线程可能造出同一个对象),是则宽容接受。
阶段 6:finally 释放锁与唤醒等待者
java
// 第 417-431 行
finally {
if (locked) {
this.singletonLock.unlock();
}
this.lenientCreationLock.lock();
try {
this.singletonsInLenientCreation.remove(beanName);
this.lenientWaitingThreads.entrySet().removeIf(
entry -> entry.getValue() == currentThread);
this.lenientCreationFinished.signalAll();
}
finally {
this.lenientCreationLock.unlock();
}
}
无论是否拿了 singletonLock,最后都要清掉宽松创建标记、signalAll() 唤醒所有在 lenientCreationFinished 上等待的线程。这就是 7.0.9 单例创建并发模型的全貌。
8. 运行机制(一):循环依赖的完整时序
8.1 setter 循环依赖是怎么被解决的
假设两个单例 Bean:A 依赖 B(字段 @Autowired B b),B 也依赖 A(字段 @Autowired A a)。容器启动时先创建 A,完整时序如下:
less
线程 T1:创建 A
getSingleton("A", ObjectFactory)
beforeSingletonCreation("A") // A 加入 singletonsCurrentlyInCreation
createBean("A")
doCreateBean("A")
createBeanInstance → new A() // A 裸对象已构造,字段 b=null
applyMergedBeanDefinitionPostProcessors
addSingletonFactory("A", () -> getEarlyBeanReference(A)) // 写入三级缓存
populateBean("A")
postProcessProperties(@Autowired B b)
resolveDependency → getBean("B")
┌── 线程 T1:创建 B ──┐
getSingleton("B", ObjectFactory)
beforeSingletonCreation("B")
createBean("B")
doCreateBean("B")
createBeanInstance → new B()
addSingletonFactory("B", () -> getEarlyBeanReference(B))
populateBean("B")
postProcessProperties(@Autowired A a)
resolveDependency → getBean("A")
getSingleton("A", true)
singletonObjects 未命中
earlySingletonObjects 未命中
singletonFactories 命中!调 lambda
→ getEarlyBeanReference(A) 返回 A 裸对象
把 A 裸对象放入 earlySingletonObjects,从 singletonFactories 移除
← 返回 A 裸对象给 B
B.a = A 裸对象 // B 的字段 a 赋值成功
initializeBean("B")
← B 完成
addSingleton("B", B 成品) // B 入一级缓存
← 回到 A 的 populateBean
A.b = B 成品 // A 的字段 b 赋值成功
initializeBean("A")
afterSingletonCreation("A")
addSingleton("A", A 成品) // A 入一级缓存,清二三级
关键节点解释:
- A 在
createBeanInstance之后、populateBean之前 就把ObjectFactory注册进了三级缓存。这是必须的时机------再晚(比如在 populateBean 之后)就来不及了,因为 populateBean 本身可能触发对 B 的创建。 - B 在 populateBean 时来 getBean("A") ,一级没有、二级没有,但三级有一个 ObjectFactory。此时 Spring 调用这个工厂,拿到 A 的早期引用(裸对象,或 AOP 代理------取决于
getEarlyBeanReference是否被AbstractAutoProxyCreator拦截)。 - A 的早期引用一旦生成,就从三级升级到二级。B 拿到的是这个早期引用。B 完成创建后入一级缓存,A 回来继续 populateBean,拿到 B 的成品。
- 最终 A 入一级缓存时,
addSingleton会把 A 的三级、二级都清掉。此后所有对 A 的 getBean 都命中一级,返回的是同一个 A 成品。
8.2 为什么需要三级而不是两级
网上常见解释是"二级缓存不够,因为要区分普通引用和代理"。这句话对,但不够精确。真正的推理是这样的:
假设只有一级(成品)+ 二级(提前暴露的对象):那么 A 在 createBeanInstance 之后就必须立刻把"提前暴露的对象"放进二级。但问题是------这个提前暴露的对象到底应该是裸 A,还是 A 的 AOP 代理?
如果 A 不需要 AOP,提前暴露裸 A 就行,成本为零。但如果 A 需要被 @Transactional 代理呢?代理对象必须在"早期暴露"时就生成,否则 B 拿到裸 A、最终容器里放的是代理 A,两者不一致。
可问题是:A 到底需不需要 AOP,要等到 postProcessAfterInitialization 阶段才能最终确定 。如果 A 根本没有发生循环依赖,B 永远不会在 A 创建中途来 getBean("A"),那 AOP 代理完全可以等 postProcessAfterInitialization 再生成,提前生成反而浪费(要多构造一个代理对象)。
三级缓存解决了这个矛盾:它存的不是对象本身,而是一个 ObjectFactory(lambda)。只有当真的发生循环依赖、B 来 getBean("A") 时,这个 lambda 才被调用 ,getEarlyBeanReference 此时才去问所有 SmartInstantiationAwareBeanPostProcessor:"要不要为这个早期引用生成代理?"不需要代理就原样返回裸对象。没有循环依赖,lambda 永远不执行,AOP 按原计划在初始化后阶段生成。
一句话:三级缓存把"是否生成代理"的决策从"构造完立刻做"推迟到"真有人要早期引用时才做",兼顾了循环依赖正确性与无循环依赖时的性能。
8.3 构造器循环依赖为什么无解
把上面时序里的 @Autowired 字段改成构造器注入:
java
public A(B b) { this.b = b; }
public B(A a) { this.a = a; }
时序变成:
css
创建 A
beforeSingletonCreation("A")
createBeanInstance
→ 需要调用 A(B b) 构造器
→ 构造器参数 B 必须现在就解析
→ getBean("B")
beforeSingletonCreation("B")
createBeanInstance
→ 需要调用 B(A a) 构造器
→ getBean("A")
getSingleton("A", true)
singletonObjects 没有
earlySingletonObjects 没有
singletonFactories ------ 也没有!
为什么三级缓存没有?因为 addSingletonFactory 是在 createBeanInstance 之后 才调用的(见 doCreateBean 第 596 行)。而构造器注入的依赖,是在 createBeanInstance 内部 、反射调用构造器时就要解析的------此时 A 对象连都还没 new 出来,根本没有"裸对象"可以放进三级缓存。三级缓存的 lambda 闭包都捕获不到 bean 变量,因为它还不存在。
所以构造器循环依赖在原理上无解:你不可能在对象还没构造完时,就把它的引用暴露给别人 。Spring 直接抛 BeanCurrentlyInCreationException,这是正确的失败,不是 bug。
8.4 allowCircularReferences=false 的行为
AbstractAutowireCapableBeanFactory 有一个 allowCircularReferences 字段(默认 true)。设为 false 后,doCreateBean 第 589 行的判断:
java
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
直接为 false,三级缓存根本不会被写入 。此时即使代码里存在 setter 循环依赖,也会在 populateBean 阶段 getBean 时因为三级缓存空而抛 BeanCurrentlyInCreationException。Spring Boot 2.6+ 默认把这个开关关掉了,目的就是强制开发者显式处理循环依赖(用 @Lazy 或重构)。
8.5 @Lazy 注入代理:打破循环依赖的另一条路
ContextAnnotationAutowireCandidateResolver(spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java)是 @Lazy 的核心。完整源码前面已读过,这里提炼机制:
java
// 第 87-108 行
protected Object buildLazyResolutionProxy(DependencyDescriptor descriptor, @Nullable String beanName) {
return buildLazyResolutionProxy(descriptor, beanName, false);
}
private Object buildLazyResolutionProxy(
DependencyDescriptor descriptor, @Nullable String beanName, boolean classOnly) {
if (!(getBeanFactory() instanceof DefaultListableBeanFactory dlbf)) {
throw new IllegalStateException("Lazy resolution only supported with DefaultListableBeanFactory");
}
TargetSource ts = new LazyDependencyTargetSource(dlbf, descriptor, beanName);
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);
Class<?> dependencyType = descriptor.getDependencyType();
if (dependencyType.isInterface()) {
pf.addInterface(dependencyType);
}
ClassLoader classLoader = dlbf.getBeanClassLoader();
return (classOnly ? pf.getProxyClass(classLoader) : pf.getProxy(classLoader));
}
当 A 的字段写成 @Lazy @Autowired B b 时,resolveDependency 在第 1651-1657 行发现 descriptor.supportsLazyResolution() 为 true(因为字段上有 @Lazy),于是调 getLazyResolutionProxyIfNecessary,返回一个 AOP 代理。这个代理的 TargetSource 是 LazyDependencyTargetSource------它内部保存着 DefaultListableBeanFactory 和 DependencyDescriptor,直到代理的方法被第一次调用时 ,getTarget() 才真正去 doResolveDependency 拿 B 对象:
java
// 第 136-199 行(节选)
@Override
public Object getTarget() {
Object cachedTarget = this.cachedTarget;
if (cachedTarget != null) {
return cachedTarget;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
Object target = this.beanFactory.doResolveDependency(
this.descriptor, this.beanName, autowiredBeanNames, null);
......
if (cacheable) {
this.cachedTarget = target;
}
return target;
}
这意味着:A 注入的不是 B 本身,而是一个"占位代理" 。A 的创建过程完全不需要 B 已经存在,循环在构造阶段就被打断。等到 A 的业务方法真正调用 b.xxx() 时,代理才第一次去容器里拿 B------此时 B 大概率已经初始化完成了。这就是 @Lazy 化解循环依赖的原理:它不依赖三级缓存,而是用代理把"依赖的解析时机"推迟到第一次方法调用。
注意 LazyDependencyTargetSource 的 cachedTarget 是 transient volatile------第一次解析到真实 Bean 后缓存起来,后续调用直接返回。如果解析到的是 singleton Bean,就缓存;如果是 prototype,不缓存(每次都重新解析)。
8.6 prototype 与自定义 scope
prototype 在 doGetBean 里的分支前面讲过:每次都新建、不进缓存。这里强调一个常被忽视的点:prototype 的销毁回调虽然在 registerDisposableBeanIfNecessary 时注册了,但 Spring 不会主动调用它 ------因为容器不持有 prototype 的引用,不知道它什么时候该销毁。AbstractBeanFactory.registerDisposableBeanIfNecessary(第 1922-1941 行)开头就是 if (!mbd.isPrototype() && requiresDestruction(...)),prototype 直接跳过注册。
自定义 scope 的代表是 SimpleThreadScope(spring-context/src/main/java/org/springframework/context/support/SimpleThreadScope.java):
java
public class SimpleThreadScope implements Scope {
private final ThreadLocal<Map<String, Object>> threadScope = NamedThreadLocal.withInitial(
"SimpleThreadScope", HashMap::new);
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Map<String, Object> scope = this.threadScope.get();
Object scopedObject = scope.get(name);
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
scope.put(name, scopedObject);
}
return scopedObject;
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
logger.warn("SimpleThreadScope does not support destruction callbacks. " +
"Consider using RequestScope in a web environment.");
}
@Override
public String getConversationId() {
return Thread.currentThread().getName();
}
}
它的存储就是一个 ThreadLocal<Map<String, Object>>:同一个线程内多次 getBean 返回同一个对象,不同线程各自一份。get(name, objectFactory) 的双参签名是 Scope 接口的核心------第二个参数是"创建工厂",由容器传入 () -> createBean(...),scope 自己决定何时调用它。注意源码里那条注释 "Do NOT modify to use Map::computeIfAbsent"------这是历史教训:computeIfAbsent 在并发下有重入风险(工厂方法内部又触发对同一个 scope Bean 的 get),所以用手动 get + put。
SimpleThreadScope 默认不注册,需要用户通过 CustomScopeConfigurer 显式注册:
java
@Bean
public CustomScopeConfigurer threadScopeConfigurer() {
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
configurer.addScope("thread", new SimpleThreadScope());
return configurer;
}
之后就可以在 Bean 上标 @Scope("thread") 使用。
9. 源码剖析(六):销毁流程
9.1 registerDisposableBeanIfNecessary:登记销毁回调
Bean 创建的最后一步(doCreateBean 第 641 行)调用 registerDisposableBeanIfNecessary,它在 AbstractBeanFactory 第 1922-1941 行:
java
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware));
}
}
}
注意三个细节:
- prototype 不登记。前面说过,容器不持有 prototype 引用,无法代它销毁。
- singleton 登记到
disposableBeansMap 。这个 Map 是LinkedHashMap,按注册顺序保存------销毁时逆序遍历。 - 自定义 scope 的销毁回调注册给 Scope 自己 。比如
requestscope 的销毁回调由RequestContextListener在请求结束时触发,而不是容器关闭时。
requiresDestruction(第 1904-1908 行)判断这个 Bean 是否真的需要销毁:要么实现了 DisposableBean / 有自定义 destroy-method,要么有 DestructionAwareBeanPostProcessor(处理 @PreDestroy)能识别它。
9.2 DisposableBeanAdapter:三种销毁方式的统一封装
DisposableBeanAdapter(spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java)把"怎么销毁这个 Bean"打包成一个 DisposableBean 对象。它的构造器(第 108-157 行)在初始化时就解析好要调哪些方法:
java
// 第 115-152 行(节选)
this.invokeDisposableBean = (bean instanceof DisposableBean &&
!(this.nonPublicAccessAllowed && ...));
String[] destroyMethodNames = inferDestroyMethodsIfNecessary(bean.getClass(), beanDefinition);
if (!ObjectUtils.isEmpty(destroyMethodNames) &&
!(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodNames[0])) &&
!beanDefinition.hasAnyExternallyManagedDestroyMethod(destroyMethodNames[0])) {
this.invokeAutoCloseable =
(bean instanceof AutoCloseable && CLOSE_METHOD_NAME.equals(destroyMethodNames[0]));
if (!this.invokeAutoCloseable) {
this.destroyMethodNames = destroyMethodNames;
List<Method> destroyMethods = new ArrayList<>(destroyMethodNames.length);
for (String destroyMethodName : destroyMethodNames) {
Method destroyMethod = determineDestroyMethod(destroyMethodName);
......
destroyMethods.add(destroyMethod);
}
this.destroyMethods = destroyMethods.toArray(Method[]::new);
}
}
它在构造期就把 @PreDestroy 方法(由 DestructionAwareBeanPostProcessor 列表传入)、DisposableBean.destroy()、自定义 destroy-method(含推断的 close() / shutdown(),见 inferDestroyMethodsIfNecessary 第 408-458 行)全部解析成 Method 对象缓存起来,避免销毁时再做反射查找。
销毁时的执行顺序在 destroy() 方法(第 197-259 行)里:
java
@Override
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
if (this.invokeDisposableBean) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
((DisposableBean) this.bean).destroy();
}
catch (Throwable ex) {
......
}
}
if (this.invokeAutoCloseable) {
......
((AutoCloseable) this.bean).close();
......
}
else if (this.destroyMethods != null) {
for (Method destroyMethod : this.destroyMethods) {
invokeCustomDestroyMethod(destroyMethod);
}
}
else if (this.destroyMethodNames != null) {
for (String destroyMethodName : this.destroyMethodNames) {
Method destroyMethod = determineDestroyMethod(destroyMethodName);
if (destroyMethod != null) {
destroyMethod = ClassUtils.getPubliclyAccessibleMethodIfPossible(destroyMethod, this.bean.getClass());
invokeCustomDestroyMethod(destroyMethod);
}
}
}
}
销毁顺序是固定的四步:
DestructionAwareBeanPostProcessor.postProcessBeforeDestruction------@PreDestroy注解的方法由InitDestroyAnnotationBeanPostProcessor在这一步执行。DisposableBean.destroy()------如果 Bean 实现了DisposableBean接口。AutoCloseable.close()------如果 Bean 实现了AutoCloseable且 destroy-method 名被推断为close。- 自定义
destroy-method(@Bean(destroyMethod="xxx")或 XML 配置)。
注意一个细节:@PreDestroy 实际上比 DisposableBean.destroy() 先执行 。这与初始化时 @PostConstruct 比 afterPropertiesSet 先执行正好对称------都是 BPP 回调在前、接口回调在后、自定义方法最后。
9.3 destroySingletons:逆序销毁
容器关闭时,DefaultSingletonBeanRegistry.destroySingletons()(第 693-718 行)被调用:
java
public void destroySingletons() {
if (logger.isTraceEnabled()) {
logger.trace("Destroying singletons in " + this);
}
this.singletonsCurrentlyInDestruction = true;
String[] disposableBeanNames;
synchronized (this.disposableBeans) {
disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
}
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
destroySingleton(disposableBeanNames[i]);
}
this.containedBeanMap.clear();
this.dependentBeanMap.clear();
this.dependenciesForBeanMap.clear();
this.singletonLock.lock();
try {
clearSingletonCache();
}
finally {
this.singletonLock.unlock();
}
}
关键点:
- 逆序遍历
disposableBeanNames(for (int i = length - 1; i >= 0; i--))。disposableBeans是LinkedHashMap,按 Bean 创建顺序插入------逆序销毁意味着"后创建的先销毁"。这符合依赖关系:A 依赖 B,B 先创建、A 后创建;销毁时 A 先销毁,B 再销毁,保证 A 在销毁过程中还能安全使用 B。 destroySingleton(第 738-768 行)内部先从disposableBeans移除 adapter,然后调destroyBean(第 776-830 行)。destroyBean还会递归销毁依赖方 :先从dependentBeanMap取出所有依赖这个 Bean 的 Bean,逐个destroySingleton------这就是为什么即使不是严格的创建顺序,依赖方也一定会在被依赖方之前销毁。- 全部销毁完后,
clearSingletonCache()清空三级缓存,并把singletonsCurrentlyInDestruction重置为 false。
9.4 与 ApplicationContext.close 的关系
AbstractApplicationContext.close()(spring-context 模块)做的事情是:发布 ContextClosedEvent → 销毁 BeanFactory 里的所有单例(调 destroySingletons())→ 关闭生命周期处理器 → 标记上下文已关闭。本章不展开 ApplicationContext 的 refresh 流程,但要明确:Bean 的销毁不是直接由 close() 逐个调 destroy() 完成的,close() 只是触发 destroySingletons(),后者再按上面的逆序逻辑处理。
一个常见错误是在 @PreDestroy 或 destroy() 方法里又去 getBean------此时 singletonsCurrentlyInDestruction 已经是 true,getSingleton(String, ObjectFactory) 第 300-304 行会直接抛 BeanCreationNotAllowedException:
java
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
错误信息本身就是最好的文档:不要在 destroy 方法里向 BeanFactory 要 Bean。
10. 扩展用法与最佳实践
10.1 自定义 BeanPostProcessor 的正确姿势
BeanPostProcessor 是扩展 Spring 生命周期最常用的手段。一个最小例子:
java
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 在 @PostConstruct / afterPropertiesSet 之前
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 在 init-method 之后,AOP 代理在这里生成
return bean;
}
}
但有几个坑必须知道:
- BPP 自身不能享受 BPP 处理 。容器在注册 BPP 时,其他 BPP 还没注册完,BPP 自己的
@Autowired可能失效。如果 BPP 需要注入依赖,优先用构造器注入,并确保它实现了PriorityOrdered或Ordered来控制执行顺序。 postProcessAfterInitialization返回值要小心 。如果你返回了一个新对象(比如代理),那这个新对象才是最终放进容器的 Bean;但循环依赖的另一方可能已经拿到了旧对象------这就是第 4.3 节那个"raw version injected"异常的来源。自定义 BPP 如果要包装 Bean,务必实现SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference,让早期引用与最终引用一致。- 不要在 BPP 里做重型逻辑。BPP 对每个 Bean 都执行一次,是热路径。耗时操作会拖慢整个启动。
10.2 构造器注入 vs setter/字段注入
从本章源码可以直接得出结论:
- 构造器注入 在
createBeanInstance阶段完成,此时 Bean 还没被任何 BPP 处理,也没进三级缓存。它的依赖在对象构造时就必须全部就绪------这就是构造器循环依赖无解的原因。好处是:依赖不可变、可以在构造完成后立刻使用、避免"半成品对象"被暴露。 - 字段/setter 注入 在
populateBean阶段完成,此时 Bean 已经构造好、已经通过addSingletonFactory暴露了早期引用。它支持循环依赖(三级缓存化解),但代价是:对象在 populateBean 之前处于"已构造但依赖未注入"的中间状态,如果有@PostConstruct依赖这些字段,要小心。
最佳实践 :能用构造器注入就用构造器注入(Spring 官方也推荐),它天然避免循环依赖------如果两个类构造器互相注入,容器启动时就报错,而不是等到运行时才暴露问题。只有当确实存在合理的循环依赖、且重构成本太高时,才用 @Lazy 打破。
10.3 循环依赖治理
基于本章源码,循环依赖的处理策略按优先级排列:
- 重构消除 :把两个 Bean 的公共逻辑抽到第三个 Bean,或用事件(
ApplicationEventPublisher)解耦。这是最优解。 @Lazy打断 :在其中一方的注入点加@Lazy,容器注入代理而非真实对象,推迟解析时机(第 8.5 节)。@DependsOn不解决循环依赖 :它只控制初始化顺序,互相@DependsOn会直接报错。allowCircularReferences=true(默认)只支持 setter/字段级单例循环依赖;构造器、prototype、@DependsOn的循环它都救不了。- Spring Boot 2.6+ 默认
allowCircularReferences=false,意味着循环依赖直接报错。如果老项目必须兼容,可以在application.properties里spring.main.allow-circular-references=true,但这是权宜之计。
10.4 Aware 接口的选择
从第 6 节的时序可知:
- 需要拿 Bean 名字 / 类加载器 / BeanFactory 本身 → 实现
BeanNameAware/BeanClassLoaderAware/BeanFactoryAware。 - 需要拿 ApplicationContext / Environment / ResourceLoader → 实现
ApplicationContextAware等(注意这些在 spring-context,spring-bean 模块没有)。 - 更推荐的方式是直接
@Autowired注入这些依赖------ApplicationContext 本身就是一个 Bean,可以被注入。Aware 接口是"容器回调"风格,注入是"主动拉取"风格,后者更灵活。
11. 常见问题与坑
11.1 为什么 getBean("xxx") 和 getBean("&xxx") 结果不一样?
见第 3.7 节。& 前缀在 transformedBeanName 时被剥掉,但 name 原始参数保留;getObjectForBeanInstance 靠 isFactoryDereference(name) 判断是否要脱壳。不带 & 返回 FactoryBean 生产的对象,带 & 返回 FactoryBean 自己。一个常见坑:FactoryBean.getObjectType() 返回 null 时,容器无法在不创建 FactoryBean 的情况下判断它生产什么类型,此时 getBean 会强制初始化 FactoryBean。
11.2 @PostConstruct 与构造器的执行顺序
构造器在 createBeanInstance 执行(第 4.4 节),@PostConstruct 在 initializeBean 的 applyBeanPostProcessorsBeforeInitialization 阶段执行(第 6.2 节)。顺序永远是:构造器 → @Autowired 字段/setter 注入 → @PostConstruct → afterPropertiesSet → init-method → postProcessAfterInitialization 。这意味着在 @PostConstruct 里所有 @Autowired 字段都已经赋值完毕,可以安全使用。
一个常见错误是在构造器里使用 @Autowired 字段------此时字段还没注入,必然是 null。
11.3 单例提前暴露的副作用
三级缓存允许循环依赖,但代价是:Bean 在 populateBean 之前就把"半成品"暴露出去了。如果这个半成品在 @PostConstruct 或 afterPropertiesSet 里做了很重的初始化(比如建立网络连接、启动线程池),而循环的另一方在拿到早期引用后立刻调用了它的方法------此时重初始化还没执行,可能拿到错误状态。
Spring 的解决方案是 getEarlyBeanReference 与 postProcessAfterInitialization 的一致性校验(第 4.3 节),但这只能防住"被包装成代理"的场景,防不住"裸对象被提前调用业务方法"。最佳实践:不要在 Bean 还没完全初始化时就让别人调到它的业务方法 ------循环依赖场景下,确保被依赖方的业务方法对"尚未初始化"的状态是容错的,或者干脆用 @Lazy。
11.4 为什么 prototype Bean 的 @PreDestroy 不执行?
第 9.1 节讲过:registerDisposableBeanIfNecessary 开头 if (!mbd.isPrototype()) 直接跳过。容器不持有 prototype 的引用,无法在合适时机销毁它。prototype 的资源清理要由用户自己负责(比如用完手动调 close),或者改用 BeanFactory.getBean 时传入 ObjectFactory / ObjectProvider 配合 try-with-resources。
11.5 7.0.9 的锁变化对并发的影响
旧版本(5.x/6.x)单例创建全程持有 synchronized (singletonObjects),意味着容器启动时即使有多个线程,单例创建也是串行的。7.0.9 改用 ReentrantLock singletonLock,并引入 lenient creation 机制:主线程拿不到锁时可以不阻塞、宽松创建 Bean,后台线程则必须等待。这提高了启动并发度,但也带来了复杂度------currentCreationThreads、lenientWaitingThreads、lenientCreationFinished 这些字段都是为了处理宽松创建下的等待与环路检测。
对应用开发者来说,这个变化基本透明;但如果在自定义 BeanFactory 或重写 getSingleton,必须意识到锁不再是 synchronized,getSingletonMutex()(第 832-836 行)在 7.0.9 已经 @Deprecated 并返回 new Object()------不要把它当锁用。
11.6 为什么有时候 @Autowired 注入的是代理而不是原始对象?
如果 Bean 被 AOP 增强(@Transactional、@Async、@Cacheable 等),postProcessAfterInitialization 会把它替换成代理。三级缓存保证循环依赖场景下早期引用也是代理(getEarlyBeanReference 在 lambda 里被调用时,AOP BPP 已经能决定是否生成代理)。但如果循环依赖 + AOP 同时出现,且 allowRawInjectionDespiteWrapping=false(默认),就会抛那个"raw version injected"异常。解决方法是给其中一方加 @Lazy,或把 AOP 切面改成不强制代理的方式。
12. 补充:几个容易被跳过的源码细节
本节补充几个在主线讲解中带过、但实际开发中会遇到的细节,帮助读者把本章串成一张完整的网。
12.1 getMergedLocalBeanDefinition 与父子 BeanDefinition 合并
doGetBean 第 296 行调用的 getMergedLocalBeanDefinition(beanName),是很多人忽略的一步。原始注册的 BeanDefinition 可能带 parentName(XML 时代常见,@Bean 时代几乎不用),运行时需要把父定义与子定义的属性合并成一个 RootBeanDefinition。合并结果会缓存(mergedBeanDefinitions Map),下次同一个 beanName 直接返回。
doGetBean 的 finally 块里有这么一行:
java
if (!isCacheBeanMetadata()) {
clearMergedBeanDefinition(beanName);
}
如果 typeCheckOnly=true(只是类型检查)且容器没有开启元数据缓存,这次合并出来的 mbd 会被清掉。这是为了避免"为了判断类型而不小心提前把 BeanDefinition 固定住"------比如动态注册 BeanDefinition 的场景,类型检查不应该污染后续的合并结果。
12.2 ConstructorResolver.autowireConstructor 在做什么
createBeanInstance 走到 autowireConstructor 时,实际委托给 ConstructorResolver.autowireConstructor(AbstractAutowireCapableBeanFactory 第 1377-1380 行只是 new 一个 ConstructorResolver 再调)。它做三件事:
- 构造器候选筛选 :从传入的
ctors(@Autowired标注的或隐式推断的)里,结合显式 args,选出最匹配的那个构造器。如果有多个候选,按参数个数、类型距离打分。 - 参数值解析 :对构造器每个参数,调用
createArgumentArray解析------如果参数值是RuntimeBeanReference,就getBean拿到依赖;如果是TypedStringValue,做类型转换。这一步就是"构造器注入的依赖在哪一步被 getBean"的答案:就在反射调构造器之前。 - 反射调用 :
bw = new BeanWrapperImpl(ctor.newInstance(argsToUse)),包成 BeanWrapper 返回。
理解了这三步,就能解释为什么构造器循环依赖无解:第 2 步 getBean 时,外层 Bean 的 createBeanInstance 还没返回,bean 变量还不存在,addSingletonFactory 自然也没被调用。
12.3 FactoryBean 产物的缓存:getObjectFromFactoryBean
第 3.7 节讲了 getObjectForBeanInstance 脱壳,但脱壳后 getObjectFromFactoryBean 内部还有一层缓存。它在 FactoryBeanRegistrySupport(spring-beans/.../factory/support/FactoryBeanRegistrySupport.java)里:如果 FactoryBean 是 singleton,getObject() 的结果会被放进 factoryBeanObjectCache;下次同一个 FactoryBean 再来 getBean,直接返回缓存,不重复调 getObject()。如果 FactoryBean 是 prototype(实现了 SmartFactoryBean.isPrototype() 返回 true),则每次都调 getObject()。
这解释了一个常见困惑:"为什么同一个 FactoryBean 注入两次,拿到的是同一个对象?"------不是因为 FactoryBean 自己是单例,而是它生产的对象被 factoryBeanObjectCache 缓存了。
12.4 ObjectProvider 与 DependencyObjectProvider
第 5.3 节提到 @Autowired ObjectProvider<UserService> 会返回一个 DependencyObjectProvider。它的实现在 DefaultListableBeanFactory 第 2507 行开始。这个对象实现了 ObjectProvider 接口,提供:
getObject():必须拿到 Bean,拿不到抛异常。getIfAvailable():拿不到返回 null,不抛异常。getIfUnique():多个候选时返回 null,不抛NoUniqueBeanDefinitionException。forEachConsumer/stream()/orderedStream():遍历所有同类型 Bean。
它的核心价值是延迟与容错 ------注入点不立刻触发依赖创建,也允许依赖缺失。在 Spring Boot 的自动配置里,大量用 ObjectProvider 做"可选依赖"。
12.5 prototype 的 ThreadLocal 防重入
doGetBean prototype 分支里的 beforePrototypeCreation(beanName) / afterPrototypeCreation(beanName) 操作的是 prototypesCurrentlyInCreation------一个 ThreadLocal<Set<String>>。它的作用与 singleton 的 singletonsCurrentlyInCreation 类似:防止两个 prototype 在构造过程中无限递归互相 getBean。但因为 prototype 没有缓存,它不能像 singleton 那样"提前暴露",检测到循环就直接抛 BeanCurrentlyInCreationException。这就是为什么 prototype 循环依赖比 singleton 更严格------连"报错"都报错得更早。
12.6 SmartInstantiationAwareBeanPostProcessor 的三个额外回调
回顾三层 BPP 接口关系:
markdown
BeanPostProcessor
└── InstantiationAwareBeanPostProcessor
└── SmartInstantiationAwareBeanPostProcessor
最顶层 SmartInstantiationAwareBeanPostProcessor 比普通 BPP 多三个方法:
predictBeanType:预测这个 Bean 最终会是什么类型(不真创建)。用于getBeanNamesForType在不实例化的情况下做类型匹配。determineCandidateConstructors:推断候选构造器。AutowiredAnnotationBeanPostProcessor实现它,就是第 4.4 节那个扫描@Autowired构造器的逻辑。getEarlyBeanReference:循环依赖时返回早期引用。AbstractAutoProxyCreator(AOP)实现它,在循环依赖场景下提前生成代理。
这三个回调分别对应 Bean 生命周期里"类型预测 → 实例化 → 早期暴露"三个特殊时刻,是 Spring 容器扩展点里最精密的一组。
12.7 beanPostProcessorCache 的分组优化
本章源码里反复出现 getBeanPostProcessorCache().instantiationAware、.smartInstantiationAware、.destructionAware。这个 cache 在 AbstractBeanFactory 里维护,把注册的 BPP 按接口类型分组缓存。为什么要这么做?因为 postProcessBeforeInstantiation、postProcessProperties、postProcessBeforeDestruction 这些方法只对特定接口的 BPP 有意义,如果每次都遍历全部 BPP 再 instanceof 判断,热路径开销不小。7.0.9 在 BPP 注册时就分好组,调用时直接取对应分组遍历。这是一个看似不起眼但影响启动性能的优化。
13. 本章小结
Bean 的生命周期可以浓缩成一条主线:
scss
getBean(name)
→ transformedBeanName(剥 &、解析别名)
→ getSingleton(beanName) 查一级缓存
命中 → getObjectForBeanInstance(FactoryBean 脱壳)→ 返回
未命中 → doGetBean 三分支:
singleton → getSingleton(name, ObjectFactory)
→ beforeSingletonCreation
→ createBean → doCreateBean
→ createBeanInstance(构造器/工厂方法/Supplier)
→ applyMergedBeanDefinitionPostProcessors(扫描 @Autowired)
→ addSingletonFactory(写三级缓存,仅 singleton+允许循环依赖)
→ populateBean
→ postProcessAfterInstantiation
→ autowire byName/byType(传统 XML)
→ postProcessProperties(@Autowired / @Resource 真正注入)
→ applyPropertyValues(XML <property> 写值)
→ initializeBean
→ invokeAwareMethods(BeanName/ClassLoader/BeanFactory)
→ applyBeanPostProcessorsBeforeInitialization
(含 @PostConstruct、ApplicationContextAwareProcessor)
→ invokeInitMethods(afterPropertiesSet → init-method)
→ applyBeanPostProcessorsAfterInitialization(AOP 代理)
→ registerDisposableBeanIfNecessary
→ afterSingletonCreation
→ addSingleton(写一级,清二三级)
prototype → createBean(不进缓存,每次新建)
自定义 scope → scope.get(name, () -> createBean(...))
→ adaptBeanInstance(类型转换)
销毁时逆序遍历 disposableBeans:@PreDestroy → DisposableBean.destroy() → AutoCloseable.close() → 自定义 destroy-method。
本章重点回顾:
doGetBean是总调度,它自己不造对象,只负责名字解析、缓存查找、按 scope 分发、FactoryBean 脱壳。doCreateBean是造对象的核心,六步顺序固定:实例化 → BPP 扫描 → 三级缓存注册 → populateBean → initializeBean → 销毁登记。- 三级缓存解决的是"构造完成但未初始化"对象的提前暴露问题 ,核心是
ObjectFactory把 AOP 代理生成推迟到真正需要时。构造器循环依赖无解,因为对象还没 new 出来就没有东西可以暴露。 - 7.0.9 的单例锁是
ReentrantLock singletonLock,不是旧版的synchronized (singletonObjects);getSingleton(String, boolean)用tryLock()快速失败,跨线程提前推断直接返回 null。同时引入了 lenient creation 机制提高启动并发度。 - 初始化时序 :
BeanNameAware等三个内联 Aware →postProcessBeforeInitialization(含@PostConstruct与ApplicationContextAware)→afterPropertiesSet→ 自定义 init-method →postProcessAfterInitialization(AOP)。 - 销毁顺序与初始化对称 :
@PreDestroy→DisposableBean.destroy()→AutoCloseable.close()→ 自定义 destroy-method;整体按 Bean 创建逆序销毁,且递归销毁所有依赖方。
本章关键类清单
| 类名 | 模块与相对路径 | 职责一句话 |
|---|---|---|
AbstractBeanFactory |
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java | doGetBean 主流程、名字解析、FactoryBean 脱壳、parent 回退 |
AbstractAutowireCapableBeanFactory |
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java | createBean/doCreateBean/populateBean/initializeBean,真正造对象 |
DefaultSingletonBeanRegistry |
spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java | 三级缓存、创建中标记、singletonLock、销毁登记与逆序销毁 |
DefaultListableBeanFactory |
spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java | resolveDependency/doResolveDependency,按类型找 Bean 的决策中心 |
BeanFactoryUtils |
spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java | transformedBeanName 剥 &、isFactoryDereference 判断前缀 |
FactoryBeanRegistrySupport(FactoryBean 产物缓存) |
spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java | FactoryBean 单例产物缓存与 getObjectFromFactoryBean |
RootBeanDefinition |
spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java | 合并后的 Bean 配方,createBean 的输入 |
ConstructorResolver |
spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java | 构造器候选筛选、参数解析、工厂方法实例化 |
BeanDefinitionValueResolver |
spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java | 把 RuntimeBeanReference/TypedStringValue 等占位值解析成运行时对象 |
BeanWrapperImpl |
spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java | 包装 Bean 实例,提供属性读写与类型转换 |
AutowiredAnnotationBeanPostProcessor |
spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java | 处理 @Autowired/@Value,推断候选构造器 |
CommonAnnotationBeanPostProcessor |
spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java | 处理 @Resource,继承 InitDestroyAnnotationBeanPostProcessor |
InitDestroyAnnotationBeanPostProcessor |
spring-context/src/main/java/org/springframework/context/annotation/InitDestroyAnnotationBeanPostProcessor.java | 处理 @PostConstruct/@PreDestroy |
ContextAnnotationAutowireCandidateResolver |
spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java | @Lazy 注入代理生成(buildLazyResolutionProxy) |
ApplicationContextAwareProcessor |
spring-context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java | 回调 ApplicationContextAware/EnvironmentAware 等上下文 Aware |
DisposableBeanAdapter |
spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java | 统一封装 @PreDestroy/DisposableBean/自定义 destroy-method 的销毁 |
SimpleThreadScope |
spring-context/src/main/java/org/springframework/context/support/SimpleThreadScope.java | 基于 ThreadLocal 的自定义 Scope 示例 |
Scope |
spring-beans/src/main/java/org/springframework/beans/factory/config/Scope.java | 自定义作用域接口,get(name, ObjectFactory) 是核心方法 |
DependencyDescriptor |
spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java | 描述一个注入点(字段/方法参数),供 resolveDependency 使用 |
InjectionMetadata |
spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java | @Autowired 注入点的元数据缓存,inject 执行反射赋值 |
掌握了这 20 个类的职责与协作关系,就掌握了 Spring Bean 生命周期的骨架。后续无论遇到循环依赖报错、AOP 失效、初始化顺序问题,都能回到本章对应的方法里找到源码根据,而不是停留在"Spring 就是这么设计的"这种模糊认知上。