Spring Bean
Spring Bean是Spring框架中由IoC容器实例化、组装和管理的对象。了解Bean的作用域、生命周期及依赖注入方式,对于有效使用Spring循环依赖至关重要。
作用域
作用域 | 描述 |
---|---|
singleton | 在Spring IoC容器中,无论有多少个Bean引用它,始终只有一个共享的Bean实例。Singleton作用域是默认设置,适用于无状态的组件。 |
prototype | 每次通过Spring容器获取prototype定义的bean时,都会创建一个新的Bean实例。这种作用域适合有状态的组件,例如需要保存用户特定数据的Bean。 |
request | 在一次Http请求中,容器返回同一个Bean实例,不同请求则产生新的实例,该Bean仅在当前Http请求内有效。 |
session | 在一个Http Session中,容器返回同一个Bean实例,不同Session则创建新的实例。类似于Request作用域,但范围更广。 |
global session | 在全局Http Session中,容器返回同一个Bean实例,主要用于Portlet上下文。 |
生命周期
Spring Bean的生命周期是由Spring IOC容器进行管理,主要包括实例化、属性赋值、初始化和销毁这四个主要阶段。了解这个周期对于使用Spring框架的开发者来说非常重要,因为它涉及到对象从创建到消亡的整个过程,而且提供了诸多自定义操作的扩展点。
讨论Spring Bean的生命周期前,要理解其由IoC(控制反转)容器进行管理的本质。Spring IoC容器负责定位、构造以及配置Bean,即管理对象从生到死的整个周期。这个生命周期的理解至关重要,因为它让开发者能够在Bean的创建、使用和销毁的各个阶段插入自定义的逻辑。
- 首先,实例化(Instantiation)过程涉及Bean的创建。当应用启动时,Spring容器会解析配置文件或注解,从而为每个声明的Bean创建一个实例。根据Bean的定义不同,这个实例化过程可能通过反射、工厂方法或是其他方式实现。
- 接着是属性赋值(Populate)阶段。一旦Bean被实例化,Spring容器会通过设置属性值来配置它。这通常涉及到依赖注入(DI),可以通过构造函数注入、字段注入或setter方法注入等方式实现,如果定义中有
@Autowired
或@Required
注解,Spring会尝试注入必要的依赖。此步骤确保了Bean在初始化之前已获得了所有必要的依赖关系。 - 第三步是初始化(Initialization)过程。在此阶段,如果定义了初始化方法(使用注解如@PostConstruct),Spring将调用这些方法允许进一步定制Bean的状态。此时,Bean已经准备好被应用程序使用。
- 最后一步是销毁(Destruction)阶段。这一步发生在Spring容器关闭或应用终止时。如果为Bean定义了销毁逻辑(如使用destroy-method属性或@PreDestroy注解),Spring将调用这些方法以释放资源或执行清理工作。
除了上述主要阶段外,Spring还提供了多个扩展点,允许开发者介入Bean的创建和使用过程。例如,BeanPostProcessor接口允许在Bean的前后初始化和销毁时执行自定义逻辑。实现了特定Aware接口的Bean(如ApplicationContextAware)能在适当的时候获取到容器的上下文信息。
实例化
实例化Bean的过程主要包括以下几个步骤:
- 解析Bean的类:首先需要确保Bean的类已经被解析,可以通过
resolveBeanClass(mbd, beanName)
方法获取Bean的类。 - 检查访问权限:如果Bean的类不是public的,并且不允许非public访问,那么会抛出一个异常。
- 使用工厂方法实例化:如果Bean定义中有工厂方法,那么会调用
instantiateUsingFactoryMethod(beanName, mbd, args)
方法来实例化Bean。 - 快捷方式:如果在重新创建相同的Bean时,可以直接使用已经解析好的构造函数或者工厂方法进行实例化。
- 自动装配构造函数:如果有候选的构造函数需要进行自动装配,那么会调用
autowireConstructor(beanName, mbd, ctors, args)
方法来进行实例化。 - 首选构造函数:如果有首选的构造函数,那么会使用这些构造函数进行实例化。
- 无参构造函数:如果没有特殊处理,那么会使用无参构造函数进行实例化。
相关源码
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] 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());
}
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);
}
属性赋值
属性赋值负责将配置的属性值或依赖注入到已经实例化的Bean中。主要包括以下几个步骤:
- 检查BeanWrapper实例:如果传入的
BeanWrapper
为null
,则检查Bean定义中是否有属性值。如果有属性值,则抛出BeanCreationException
,因为没有实例可以应用这些属性值。如果没有属性值,则跳过属性赋值阶段。 - 检查是否是记录类:如果Bean是Java 14引入的记录类(record),则检查是否有属性值。记录类是不可变的,因此不允许在创建后修改属性值。如果有属性值,则抛出异常;如果没有,则跳过属性赋值。
- 调用
InstantiationAwareBeanPostProcessors
:如果Bean不是合成的(即不是由容器内部创建的),并且存在InstantiationAwareBeanPostProcessor
,则调用它们的postProcessAfterInstantiation
方法。这些后处理器可以在属性赋值之前修改Bean的状态,例如支持字段注入。如果后处理器返回false
,则跳过属性赋值。 - 获取属性值:从Bean定义中获取属性值。如果定义中有属性值,则使用这些值;如果没有,则设置为
null
。 - 根据自动装配模式处理属性值:如果Bean定义了自动装配模式(
AUTOWIRE_BY_NAME
或AUTOWIRE_BY_TYPE
),则根据这些模式创建一个新的MutablePropertyValues
实例,并添加相应的属性值。 - 调用
InstantiationAwareBeanPostProcessors
进行属性值处理:如果存在InstantiationAwareBeanPostProcessor
,则调用它们的postProcessProperties
方法,允许它们修改属性值。如果返回的属性值为null
,则跳过属性赋值。 - 依赖检查:如果Bean定义了依赖检查模式,则进行依赖检查。这确保了所有必要的依赖项都已正确设置。
- 应用属性值:如果属性值不为
null
,则调用applyPropertyValues
方法将属性值应用到Bean实例上。
相关源码
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. This can be used, for example,
// to support styles of field injection.
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);
}
}
初始化
Bean的初始化逻辑包括执行Aware接口方法、初始化方法和BeanPostProcessor的后处理器。
主要包括以下几个步骤:
- 执行Aware接口方法:调用
invokeAwareMethods
方法,如果Bean实现了Aware接口(如BeanNameAware、BeanFactoryAware等),则执行相应的Aware接口方法。 - 调用BeanPostProcessor的beforeInitialization方法:如果Bean不是合成的,调用
applyBeanPostProcessorsBeforeInitialization
方法,允许BeanPostProcessor在Bean的初始化方法执行之前进行处理。 - 执行初始化方法:调用
invokeInitMethods
方法,执行Bean的初始化逻辑。这包括执行实现InitializingBean
接口的afterPropertiesSet
方法和自定义的初始化方法。 - 处理初始化异常:如果初始化过程中发生异常,捕获异常并抛出
BeanCreationException
。 - 调用BeanPostProcessor的afterInitialization方法:如果Bean不是合成的,调用
applyBeanPostProcessorsAfterInitialization
方法,允许BeanPostProcessor在Bean的初始化方法执行之后进行处理。 - 返回处理后的Bean实例:返回经过Aware接口方法、初始化方法和BeanPostProcessor处理后的Bean实例。
相关源码
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
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的销毁负责在容器关闭或Bean不再需要时执行清理工作。主要包括以下几个步骤:
- 检查Bean是否为原型类型:如果Bean定义是原型类型的(即每次请求都会创建一个新的Bean实例),则不需要注册销毁回调,因为原型Bean的生命周期是由容器之外的代码控制的。
- 检查是否需要销毁Bean:如果Bean不是原型类型的,并且需要销毁(即Bean定义中指定了销毁逻辑),则继续执行销毁回调的注册。
- 注册单例Bean的销毁回调:如果Bean是单例类型的,则使用
DisposableBeanAdapter
来注册销毁回调。DisposableBeanAdapter
是一个适配器,它提供了DisposableBean
接口的实现,可以调用Bean的销毁方法,同时也可以处理Bean定义中的自定义销毁逻辑。 - 注册自定义作用域Bean的销毁回调:如果Bean不是单例类型的,则根据Bean定义的作用域(如
session
、request
等)查找对应的作用域,并使用该作用域来注册销毁回调。作用域负责在Bean不再需要时执行销毁逻辑。 - 处理作用域不存在的情况:如果作用域不存在,抛出
IllegalStateException
,因为Spring容器需要为每个作用域注册对应的销毁逻辑。
相关源码
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));
}
}
}
依赖注入方式
构造器注入:
- 描述:通过构造器参数来注入依赖。
- 优点:强制依赖,不可变性,易于单元测试。
- 示例:java
public class ExampleBean { private final Dependency dependency; @Autowired public ExampleBean(Dependency dependency) { this.dependency = dependency; } }
Setter注入:
- 描述:通过setter方法来注入依赖。
- 优点:保持了JavaBean的标准。
- 示例:java
public class ExampleBean { private Dependency dependency; @Autowired public void setDependency(Dependency dependency) { this.dependency = dependency; } }
字段注入:
- 描述:直接在字段上使用
@Autowired
注解来注入依赖。 - 优点:简洁。
- 示例:java
public class ExampleBean { @Autowired private Dependency dependency; }
- 描述:直接在字段上使用
接口注入(也称为方法注入):
- 描述:较少使用,通过实现特定接口的方法来注入依赖。
- 示例:
查看代码
javapublic interface InjectionAware { void setInjection(Dependency dependency); } public class ExampleBean implements InjectionAware { private Dependency dependency; @Override public void setInjection(Dependency dependency) { this.dependency = dependency; } }
Spring 循环依赖
循环依赖是指在依赖关系中形成了闭环,造成循环调用的现象。在Spring框架中,循环依赖通常发生于Bean之间的依赖关系。当Spring容器创建Bean时,如果一个Bean在创建过程中需要依赖另一个尚未创建完成的Bean,而后者又依赖于前者,这样就会形成一个闭环,导致无限循环的调用。
循环依赖的类型
自我依赖
一个Bean依赖于自身
@Component
public class A {
private A a;
@Autowired
public A(A a) {
this.a = a;
}
}
直接依赖
两个Bean直接相互依赖。(构造器循环依赖)
查看代码
@Component
public class B {
private C c;
@Autowired
public B(C c) {
this.c = c;
}
}
@Component
public class C {
private B b;
@Autowired
public C(B b) {
this.b = b;
}
}
间接依赖
多个Bean形成间接的循环依赖。
查看代码
@Component
public class D {
private E e;
@Autowired
public D(E e) {
this.e = e;
}
}
@Component
public class E {
private F f;
@Autowired
public E(F f) {
this.f = f;
}
}
@Component
public class F {
private D d;
@Autowired
public F(D d) {
this.d = d;
}
}
循环依赖的解决条件
如果是构造器循环依赖和原型Bean循环依赖,Spring将无法解决循环依赖。
- 出现循环依赖的Bean必须是单例,单例(singleton)作用域的 Bean 是在整个应用程序上下文中只创建一次,并在整个应用程序生命周期中都存在。
- 依赖注入的方式不能全是构造器注入的方式,如A中注入B的方式为setter方法,B中注入A的方式为构造器,这种情况也能解决循环依赖。
不能解决的循环依赖
构造器循环依赖
Spring 使用了三级缓存机制,通过提前暴露一个尚未完全初始化的 Bean 实例来解决循环依赖。但是这种机制无法处理构造器循环依赖,因为在实例化对象时,构造器注入是最先进行的,Spring 解决循环依赖问题依靠的三级缓存在属性注入阶段,因此无法提前暴露一个半成品的 Bean 实例。
原型Bean循环依赖
原型(prototype)作用域的 Bean 是在每次被请求时都会创建一个新的实例。
举个例子,类 A 的实例依赖类 B 的实例,而类 B 的实例又依赖类 A 的实例,形成了循环依赖。
如果这两个 Bean 都是原型作用域的,那么当它们被请求时,Spring 将分别创建 A 和 B 的实例。在创建 A 的实例时,Spring 会注入一个新创建的 B 的实例;而在创建 B 的实例时,Spring 会注入一个新创建的 A 的实例。由于每次创建的实例都是新的,它们无法提前暴露给对方,导致无法解决属性注入循环依赖的问题。
相关源码解读
doGetBean
下面这段代码是Spring框架中AbstractBeanFactory
类的doGetBean
方法的实现,它是Spring容器获取Bean实例的核心方法。
源码
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);// 第一次调用getSingleton方法
if (sharedInstance != null && args == null) {
// ...
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// ...
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
// ...
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {// 第二次调用getSingleton方法,参数不同
try {
return createBean(beanName, mbd, args);// 参数中传createBean方法
}
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);
}
else if (mbd.isPrototype()) {
// ...
}
else {
// ...
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
解析
主要步骤
- 转换Bean名称:将传入的Bean名称转换为真正的Bean名称(处理别名等)。
- 尝试从单例缓存中获取Bean:如果Bean是单例,并且已经存在于单例缓存中,则直接返回该Bean的实例。
- 处理原型作用域的循环依赖:如果当前Bean正在创建中,并且是原型作用域的Bean,则抛出异常,因为Spring无法处理原型作用域Bean的循环依赖。
- 委派给父BeanFactory:如果当前BeanFactory不包含Bean定义,则委派给父BeanFactory获取Bean。
- 标记Bean为已创建:如果Bean尚未创建,则将其标记为已创建。
- 处理依赖:如果当前Bean依赖于其他Bean,则先创建依赖的Bean。
- 创建Bean实例:根据Bean的作用域(单例、原型、其他自定义作用域)来创建Bean实例。
- 处理创建Bean过程中的异常:如果在创建Bean的过程中发生异常,则进行清理工作,并抛出异常。
- 返回Bean实例:将创建的Bean实例返回给调用者。
功能说明
- getSingleton:尝试从单例缓存中获取Bean实例。如果Bean正在创建中,可能会返回一个尚未完全初始化的Bean实例。
- isPrototypeCurrentlyInCreation:检查指定的原型Bean是否正处于创建过程中,如果是,则抛出异常。
- getParentBeanFactory:获取父BeanFactory,用于处理Bean定义的委派。
- markBeanAsCreated:将指定的Bean标记为已创建,以避免重复创建。
- getMergedLocalBeanDefinition:获取合并后的Bean定义,处理继承和依赖等。
- checkMergedBeanDefinition:检查合并后的Bean定义是否有效。
- getSingleton(重载方法):创建单例Bean实例,如果需要,则将其放入单例缓存中。
- createBean:创建新的Bean实例,这是实际创建Bean的地方,涉及构造函数、属性注入、初始化等过程。
- getObjectForBeanInstance:对创建的Bean实例进行处理,例如处理FactoryBean的情况。
- adaptBeanInstance:根据需要返回Bean实例,可能涉及类型转换。
getSingleton
doGetBean
中有可能调用两次getSingleton
方法,参数不同。
第一次调用getSingleton
目的是为了从缓存池检查是否已经有了单例Bean实例。如果找到了这样的实例,那么直接返回即可。
第二次调用getSingleton
通常发生在处理循环依赖时,当某个Bean依赖于另一个正在创建中的Bean。在这种情况下,Spring会首先创建一个“早期”版本的依赖Bean实例,并将其存储在特殊的缓存中(通常是earlySingletonObjects
Map)。这样,即使依赖Bean尚未完全初始化,当前Bean也可以使用这个“早期”版本的实例继续其初始化过程。
源码
第一次调用的getSingleton方法:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 快速检查单例缓存中是否存在已经创建的Bean实例
Object singletonObject = this.singletonObjects.get(beanName);
// 如果单例缓存中没有找到实例,并且该Bean正在创建过程中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 尝试从早期单例对象缓存中获取Bean的早期引用
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果早期单例对象缓存中也没有找到,并且允许获取早期引用
if (singletonObject == null && allowEarlyReference) {
// 加锁以确保线程安全,同时防止重复创建单例Bean
synchronized (this.singletonObjects) {
// 再次检查单例缓存,因为在加锁之前可能已经有其他线程创建了Bean
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();
// 将创建的早期引用放入早期单例对象缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
// 从单例工厂缓存中移除对应的工厂对象
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
// 返回获取到的Bean实例,可能是完全初始化的实例,也可能是早期引用
return singletonObject;
}
getSingleton
通过几个Map(singletonObjects
、earlySingletonObjects
和singletonFactories
)来管理Bean的创建过程,特别是在处理循环依赖时,通过允许早期引用尚未完全初始化的Bean实例来解决循环依赖问题。这种方法保证了Bean的正确创建顺序,同时也提高了系统的性能。
第二次调用的getSingleton方法:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 验证beanName不为null
Assert.notNull(beanName, "Bean name must not be null");
// 使用同步锁来确保线程安全
synchronized (this.singletonObjects) {
// 从单例对象缓存中尝试获取Bean实例
Object singletonObject = this.singletonObjects.get(beanName);
// 如果单例对象不存在,并且当前BeanFactory中的单例对象正在销毁中
if (singletonObject == null && this.singletonsCurrentlyInDestruction) {
// 抛出一个异常,因为在BeanFactory的销毁方法实现中不允许请求Bean
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!)");
}
// 如果启用了调试日志,记录创建共享单例Bean的日志
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 调用beforeSingletonCreation方法,进行创建前的准备工作
beforeSingletonCreation(beanName);
// 标记是否创建了新的单例
boolean newSingleton = false;
// 标记是否记录抑制的异常
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
// 如果需要记录抑制的异常,则创建一个LinkedHashSet
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
// 尝试创建单例对象
try {
singletonObject = singletonFactory.getObject();// 实际调用的是参数中的createBean方法
newSingleton = true;
}
catch (IllegalStateException ex) {
// 如果单例对象在创建过程中意外出现,则使用它
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
// 记录抑制的异常
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
// 调用afterSingletonCreation方法进行创建后的清理工作
afterSingletonCreation(beanName);
// 如果创建了新的单例Bean,将其添加到单例对象缓存中
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
}
// 返回创建的单例Bean实例
return singletonObject;
}
doCreateBean
createBean
方法实际调用到doCreateBean
方法。
doCreateBean
方法是Spring容器创建和初始化单例Bean的核心逻辑。它处理了Bean的实例化、合并Bean定义的后处理、填充属性、初始化、处理循环依赖以及注册可销毁的Bean等多个方面,涵盖了Bean的生命周期。
源码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 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;
}
// 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();
}
}
// 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));
}
// 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;
}
else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
}
}
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 = new LinkedHashSet<>(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. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);// 注册销毁
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
主要逻辑
实例化Bean:
- 如果Bean是单例作用域并且已经在
factoryBeanInstanceCache
中存在,则直接获取。 - 否则,创建一个新的Bean实例。
- 如果Bean是单例作用域并且已经在
合并Bean定义的后处理:
- 应用
BeanDefinitionPostProcessor
对合并后的Bean定义进行后处理。
- 应用
处理循环依赖:
- 如果Bean是单例作用域,并且允许循环引用,并且当前Bean正处于创建过程中,那么将Bean实例放入
earlySingletonExposure
状态。
- 如果Bean是单例作用域,并且允许循环引用,并且当前Bean正处于创建过程中,那么将Bean实例放入
填充Bean属性:
- 使用依赖注入等方式填充Bean的属性。
初始化Bean:
- 调用初始化方法,例如实现
InitializingBean
接口的afterPropertiesSet
方法,或者通过init-method
属性指定的方法。
- 调用初始化方法,例如实现
处理早期暴露的单例:
- 如果之前进行了早期暴露,那么检查依赖的Bean是否已经使用了早期版本的单例。
注册可销毁的Bean:
- 如果Bean实现了
DisposableBean
接口或指定了destroy-method
,则注册为可销毁的Bean。
- 如果Bean实现了
返回初始化后的Bean实例.
代码解析
实例化Bean:
- 如果是单例并且已经存在于
factoryBeanInstanceCache
中,则直接获取。 - 否则,通过
createBeanInstance
方法创建一个新的Bean实例。
- 如果是单例并且已经存在于
合并Bean定义的后处理:
- 应用
BeanDefinitionPostProcessor
进行后处理,这包括对Bean定义的修改等。
- 应用
处理循环依赖:
- 如果允许循环引用,并且Bean处于创建过程中,那么将Bean实例放入
earlySingletonExposure
状态,以便其他Bean可以提前使用。 - 这里使用了一个临时的单例工厂来提供早期的引用。
- 如果允许循环引用,并且Bean处于创建过程中,那么将Bean实例放入
填充Bean属性:
- 通过
populateBean
方法填充Bean的属性。
- 通过
初始化Bean:
- 通过
initializeBean
方法调用初始化方法。
- 通过
处理早期暴露的单例:
- 如果之前进行了早期暴露,那么检查依赖的Bean是否已经使用了早期版本的单例。
- 如果依赖的Bean使用了早期版本的单例,并且这些依赖的Bean在Bean被包装后仍然存在,那么会抛出异常。
注册可销毁的Bean:
- 如果Bean实现了
DisposableBean
接口或指定了destroy-method
,则通过registerDisposableBeanIfNecessary
方法注册为可销毁的Bean。
- 如果Bean实现了
返回初始化后的Bean实例:
- 返回经过初始化后的Bean实例。
循环依赖的解决方法
简单的循环依赖
Spring处理循环依赖的主要策略是使用三级缓存。
- 一级缓存(singletonObjects):这个缓存中存储的是已经完全创建好的单例Bean。
- 二级缓存(earlySingletonObjects):这个缓存中存储的是已经完成实例化但还未进行属性注入和初始化的Bean。
- 三级缓存(singletonFactories):这个缓存中存储的是提前暴露的单例工厂,也就是Bean的工厂方法。
三级缓存存在于DefaultSingletonBeanRegistry
类中。
我们以两个相互依赖的Bean A和B为例来分析这个过程。
创建A的过程:
- Spring开始创建Bean A,首先检查一级缓存是否有A,没有则进入实例化阶段。
- 接下来,Spring尝试进行属性注入,发现A依赖B,于是调用getBean(b)来创建B。
创建B的过程:
- Spring开始创建Bean B,首先检查一级缓存是否有B,没有则进入实例化阶段。
- 接下来,Spring尝试进行属性注入,发现B依赖A,于是调用getBean(a)来创建A。
这个时候,Spring发现getBean(a)会再次回到创建A的流程,似乎形成了一个循环,但实际上Spring已经准备好了解决方案。
解决循环依赖:
- 当Spring创建A时,一旦实例化完成,就会将其工厂对象(singletonFactory)添加到三级缓存。
- 当Spring在创建B时,由于B依赖A,它调用getBean(a)。但此时还轮不到真正创建A,而是在三级缓存中获取到了A的工厂对象。
- Spring通过这个工厂对象得到A的早期引用(exposedObject),将这个早期引用放到二级缓存中,就可以删除三级缓存中的工厂了。这个引用虽然不是最终的Bean实例,但它已经是可以使用的对象。
- 然后Spring将这个早期引用注入到B中,而不是将B等待A完全创建好后再注入。
由于B已经有了A的早期引用,即使A还没有完全创建好,也不会影响B的使用。然后Spring继续完成A的创建和初始化过程,并在完成后将A放入一级缓存。
总结:
- 三级缓存使得Spring能够在创建Bean的过程中提前暴露Bean的早期引用,这样即使Bean之间存在循环依赖,也能通过早期引用来解决。
- 循环依赖的解决并不依赖于二级缓存earlySingletonObjects,而是依赖于三级缓存singletonFactories和早期引用。
结合AOP的循环依赖
在Spring中,如果一个Bean(比如Bean A)被AOP代理,那么从容器中获取的实际上是A的代理对象,而不是A本身。因此,在Bean B需要注入Bean A的情况下,注入的自然也是A的代理对象,这保证了AOP的相关逻辑(如事务、安全等)能够被正确应用。
AOP代理与Bean缓存
在Spring框架中,AOP代理的创建并不是在Bean实例化阶段立即进行的,而是延迟到Bean生命周期的后期,即在属性注入和初始化完成后。这是因为Spring容器利用了后置处理器AnnotationAwareAspectJAutoProxyCreator
在Bean的初始化阶段来创建代理。
三级缓存的作用
Spring的三级缓存机制(singletonFactories
)是为了解决循环依赖问题而设计的。当一个Bean被实例化后,其早期引用(即工厂对象)会被放入三级缓存。这个工厂对象可以返回该Bean的实例,也可以返回该Bean的代理对象。只有在发生循环依赖时,才会使用这个工厂对象返回对应的实例或提前创建代理。如果没有循环依赖,三级缓存不会被使用,Bean的对象代理会在后置处理器中生成,而不是提前生成。
二级缓存与AOP代理
若采用二级缓存来处理循环依赖问题,那么在Bean实例化之后,就需要立即进行AOP代理的创建,并将代理对象存入二级缓存。这样做是为了满足循环依赖中的引用需求,随后再进行属性注入和初始化,最终将Bean存入一级缓存的单例池中。
然而,这种方式并不符合Spring框架的设计理念。按照Spring的设计原则,AOP代理应当是在Bean的初始化阶段,通过后置处理器来创建的。因此,这种做法会破坏Spring原有的设计逻辑。
相比之下,三级缓存机制确保了只有当出现循环依赖时,相关对象才会提前完成代理。对于其他非循环依赖的Bean,它们的代理依然是在后置处理器阶段生成,而不是在实例化阶段就提前创建。这样的设计既维护了Spring框架的一致性,又确保了AOP代理的正确应用时机。