spring 源码解析之 createBean
前言
源码解析
getSingleton
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 获取单例 bean
Object singletonObject = this.singletonObjects.get(beanName);
// bean 实例为空,则创建单例bean
if (singletonObject == null) {
// 判断,如果当前beanFactory正在被销毁则直接抛出异常,不允许创建单例bean
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!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 做一些bean创建前的准备工作: 记录beanName 正在加载的状态(添加到 singletonsCurrentlyInCreation 缓存中),
// 若bean已经正在加载,则抛出异常。为了解决循环引用的问题
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
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 {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 从singletonsCurrentlyInCreation删除正在记录创建中的beanName
afterSingletonCreation(beanName);
}
// 添加到singletonObjects缓存中 从二级缓存 三级缓存中移除
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
this.singletonObjects.get(beanName)
:再次尝试从缓存中获取bean,若获取到,就大吉大利直接返回。若为空,则需要创建 bean。if (this.singletonsCurrentlyInDestruction)
:未获取到检测bena是否正在销毁,若是则抛出异常beforeSingletonCreation
方法中记录bean正在创建的状态将beanName添加到singletonsCurrentlyInCreation集合中)。在循环依赖时可根据此判断。singletonObject = singletonFactory.getObject()
:调用 ObjectFactory.getObject() 方法来实例化bean- afterSingletonCreation 方法
移除bean
正在夹杂的状态 - addSingleton(beanName, singletonObject): 对
各种缓存状态
做处理。
beforeSingletonCreation
这个方法并非一个空方法
,重点是!this.singletonsCurrentlyInCreation.add(beanName)
, 记录beanName正在加载
的状态(添加到singletonsCurrentlyInCreation
缓存中)
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
创建bean - createBean概述
这个方法这行代码才是重头:
singletonObject = singletonFactory.getObject();
这一行代码实则就是调用doGetBean
下的createBean
createBean
是根据给定的bean名称(beanName
)和根bean定义(RootBeanDefinition
对象mbd)创建并初始化
一个Bean实例
,上面一系列的操作都是创建bean 做准备工作的。现在开始真正来创建 bean 了,下面看源码
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] 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, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 1. 锁定class, 根据mdb和 beanName 解析出来 bean的class类型
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
// 此方法的主要作用是验证和准备Bean的方法重写。
// 这个方法会遍历Bean的所有方法,如果一个方法只被重载了一次,那么就设置overloaded为false,以避免参数类型的检查。因为这个检查很耗性能
// 这样在后续调用的时候便可以直接使用找到的方法,而不需要进行方法的参数匹配了。此外,这个方法还可以提前对方法存在性进行验证。
// 为了优化方法的调用,提高程序的运行效率。
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.
// 调用BeanProcessors的方法来替代真正的实例
// 给BeanPostProcessors一个返回代理而不是目标bean实例的机会
// 如果处理器返回了代理,那么就直接返回代理,不再进行后续的初始化操作。
// 这个方法可以让用户使用处理器来创建 bean 实例,不通过 spring 来创建 bean 实例。
//InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation : 在bean初始化前调用
//BeanPostProcessor#postProcessAfterInitialization : 在bean初始化后调用
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);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
可以看到,createBean 的整体流程大致如下:
-
解析并锁定Bean Class:确保在这一阶段解析出
实际的Bean类
,并在需要时克隆mbd以存储动态解析得到的Class(由于某些原因无法存储在共享合并的bean定义中)。具体做法是调用resolveBeanClass(mbd, beanName)方法。resolveBeanClass(mbd, beanName)
方法用于根据给定的RootBeanDefinition (mbd) 和 beanName 来获取实际的Bean类
(即Java Class对象)- 判断条件resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null表示:
-
resolvedClass != null
: 确保已经成功解析出一个Class对象。!mbd.hasBeanClass()
: 检查当前的RootBeanDefinition是否已经包含了一个已知的Class引用(例如,它可能是从XML或注解配置中读取的)。mbd.getBeanClassName() != null
: 确认RootBeanDefinition中包含了可用于查找类名的字符串信息。- 如果满足这些条件,则创建一个新的RootBeanDefinition实例(mbdToUse),将
原始mbd的其他属性复制过来
,并使用刚解析得到的Class对象(resolvedClass
)来设置新的Bean定义的Class属性
。
这样做的原因在于,原始的RootBeanDefinition可能存储的是一个类名字符串而不是Class对象本身,而在后续处理过程中,有时需要直接操作Class对象进行更高效的操作,比如反射调用、生成代理类等。
-
准备方法重写:通过调用
mbdToUse.prepareMethodOverrides()
来验证和准备Bean的方法重写
。这个过程会遍历Bean的所有方法,优化后续对方法的调用,提高运行效率
,同时提前进行方法存在性验证。 -
应用BeanPostProcessor:在真正实例化Bean之前,提供一个机会让注册的
InstantiationAwareBeanPostProcessor
或BeanPostProcessor
通过resolveBeforeInstantiation(beanName, mbdToUse)
方法返回代理对象替代目标Bean实例。如果处理器返回了非空代理对象,则直接返回该代理对象,不再继续执行后续的Bean初始化流程。 -
创建并初始化Bean实例:如果没有
BeanPostProcessor
返回代理对象或者返回的对象为空,函数将调用doCreateBean(beanName, mbdToUse, args)
方法来实际地创建并初始化Bean实例。此方法内部包含了依赖注入、属性填充以及调用初始化方法等一系列操作。 -
异常处理:在整个创建过程中,函数会捕获并处理可能出现的任何异常,包括但不限于
BeanCreationException
和ImplicitlyAppearedSingletonException
。若出现异常,函数会抛出相应的异常信息,其中包含有关异常发生的上下文,以便于调试定位问题。 最终,当Bean实例成功创建并初始化完成后,函数返回该Bean实例。
prepareMethodOverrides
这里我又理解了好久,主要一开始看到这里说的
方法重写
就想到了方法重载与重写
的那个,其实这里所说的是不一样
的。这里主要是理解
lookup-method
和replaced-method
两个属性与@Override
这玩意是不一样的。
总的来说,@Override是在编译时确定的,它要求子类的方法必须与父类的方法完全相同。而Spring的lookup-method和replace-method是在运行时确定的,它们可以动态地改变方法的行为。
看一下源码
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exist and determine their overloaded status.
// 判断是否有方法需要重写
if (hasMethodOverrides()) {
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
// 获取对应的类中的对应方法名的个数
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
// 等于0抛出异常。上面已经验证有方法需要覆盖,这里为0肯定错误
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
else if (count == 1) {
// 标记 MethodOverride 暂未被覆盖,避免参数类型检查的开销
// Mark override as not overloaded, to avoid the overhead of arg type checking.
mo.setOverloaded(false);
}
}
在Spring配置中存在lookup-method和replace-method时,这两个配置在加载xml的时候就会统一存放在BeanDefinition中的methodOverrides属性里。当创建bean的时候,AbstractAutowireCapableBeanFactory类会调用prepareMethodOverride方法来准备方法的覆盖。
知道上面这些概念与MethodOverrides这个属性的来历就很简单了,如果没有需要覆盖的,就不做处理,如果有,则判断是否超过 1 个,等于 1 个就
mo.setOverloaded(false);这个方法主要就是验证并准备给定的方法覆盖。为了之后创建 bean 时,是否需要检测参数。因为在创建 bean 的时候,一个方法可能会有多种入参方式,而最终在实例化的时候就要确定使用哪个构造函数,这个检测就很耗性能,所以做一个标记位
。
resolveBeforeInstantiation
该方法主要是调用 InstantiationAwareBeanPostProcessor 来进行一些处理,这里实际上是给了
用户一次代替Spring来创建bean
的机会,代码实现上非常简单直接调用的后处理器方法,就是有几个概念这里要提一下的。
protected 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.
// 当前类并非合成类 && 存在 BeanPostProcessor (后处理器)
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 1. 获取目标类
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 2. 先用实例前的后处理器获取 bean
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 3. 前置没有则再使用后处理器应用
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
什么是合成类?什么是非合成类?为什么合成类不能使用BeanPostProcessor进行预处理?
- 合成的含义是:这些构造体是由
Java编译器引入
的,并且在源代码中没有相应的构造体。这些合成构造体通常是编译器为了实现某些特性
(如内部类访问外部类的私有成员)而生成的。例如,当AOP
需要创建一个代理
来拦截某个类的方法调用时,它可能会生成一个新的类(代理类
),这个类在源代码中并不存在,因此它是合成的
。这个代理类会包含一些额外的逻辑,比如在调用目标方法前后插入切面的代码。 - 而非合成的则直接来自
源代码
。 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()
方法是在Bean实例化之前被调用的,它的主要目的是允许我们在Bean实例化之前进行一些自定义的处理
。但是,对于合成的类,由于它们是由编译器生成的,因此我们可能无法在Bean实例化之前对它们进行有效的处理(这个属于处理器的知识,后面会讲
)。
doCreateBean
见名知意,这是一个创建 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);
}
// 创建 bean 实例,并使用BeanWrapper包装器类来封装这个实例
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 获取 bean 实例
Object bean = instanceWrapper.getWrappedInstance();
// 获取 bean 的类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
// 设置目标解析类型
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
// 对合并后的bean定义进行同步锁定,确保其仅被后处理器修改一次
synchronized (mbd.postProcessingLock) {
// 未经过后置处理器处理
if (!mbd.postProcessed) {
try {
// 应用合并bean定义的后处理器,允许对bean的定义进行扩展或修改
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));
// 如果bean是单例且允许循环引用,在创建过程中就将bean放入单例缓存中,以解决可能存在的循环依赖问题
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.
// 暴露在缓存中的 bean 实例
Object exposedObject = bean;
try {
// 注入属性
populateBean(beanName, mbd, instanceWrapper);
// 初始化bean实例
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) {
// 从缓存获取 bean 实例,此时缓存中的 bean 实例已经完成了初始化
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果暴露的 bean 实例与一开始的原始 bean 实例相同,那么将 exposeObject 替换为 从缓存中获取已经实例化完成的 bean
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// allowRawInjectionDespiteWrapping:允许在包装后仍然注入原始类型
// hasDependentBean:有依赖当前 bean 的其他 bean
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 获取依赖当前 bean 的其他 bean
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
// 移除给定bean名称的singleton实例(如果有的话),但前提是它没有用于类型检查以外的其他目的。
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
// 能进来 则证明当前bean 的依赖 bean 还没有创建完成,还是使用的原始的 bean
actualDependentBeans.add(dependentBean);
}
}
// 如果actualDependentBeans不为空,则证明当前 bean 还有依赖 bean 还没有创建完成,那么抛出异常
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 {
// 根据Scopse 注册bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
============================
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
至此,下一篇将详细解析 doCreateBean,到底是怎么一步步创建bean 的