概要
过度
我们上节大概过了一下获得 bean 实例的总体思路,本节从单例、原型两种生命周期情况切入,对创建 bean实例 及填充属性、初始化的所有内部逻辑做详细介绍。
内容简介
对创建 bean实例 及填充属性、初始化的所有内部逻辑做详细介绍。
所属环节
创建 Bean 实例及初始化
上下环节
上文:完成 beanId 的一些基本校验,满足了前置 Bean 的实例化和初始化
下文:对获得的初始化好的实例进行FactoryBean
和&
的一通折腾
源码解析
入口
我们直接引一个代码段,包括了单例生命周期和原型生命周期的创建 Bean 的准备操作:
if (mbd.isSingleton()) {
// 完成对应 bean 实例的创建
// 单例 bean 需要一系列工序,例如加锁、缓存、注册单例等等
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建 bean 实例
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
// 构建失败记得清一下你预存的引用,防止出错
destroySingleton(beanName);
throw ex;
}
});
// 转化成我们需要的实例类型 【 FactoryBean ?Bean?】
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
// 原型 bean 保存一下就行,不是为了解决循环依赖,只是为了在创建时发现正在创建中,能快速失败
Object prototypeInstance = null;
try {
// 这个保存操作我真 TM 醉了,真的是一切靠约定
// 好在是 ThreadLocal ,不会出现多个线程同时创建多个导致最后访问出现问题
// TODO: 这个和单例一样的缓存标记不清楚有什么扩展作用,后面注意一下
// 至少能确定的是,可以用来做监视器扩展。。。。
beforePrototypeCreation(beanName);// 存一下,在创建中
// 原型模式,不用 getSingleton() 那样加锁了,直接创建
prototypeInstance = createBean(beanName, mbd, args);
} finally {
afterPrototypeCreation(beanName);// 创建完,删了标记
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
单例 Bean
创建 Bean 实例的操作很简单,因为和单例有关的创建钩子、创建完成后的单例注册,都在之前介绍的getSingleton()
中记录了(DefaultSingletonBeanRegistory
)。我们之前在介绍那个函数时基本都说明白了,这里我们穿进去的工厂方法很简单——调用createBean()
,调用失败就销毁它。
原型 Bean
调用createBean
,因为没有getSingleton()
那样用singletonsCurrentlyInCreation
有封装好的状态展示集合。自行调用两个钩子,用线程变量来做一层限制——注意,是线程变量,原型就是用来重复创建的,所以不用跨线程的限制,这里仅仅是为了防止循环依赖。
ThreadLocal
变量
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<>("Prototype beans currently in creation");
创建前后的钩子,防止此线程因循环依赖进入循环创建。
/**
* Callback before prototype creation.
* <p>The default implementation register the prototype as currently in creation.
*
* @param beanName the name of the prototype about to be created
* @see #isPrototypeCurrentlyInCreation
*/
@SuppressWarnings("unchecked")
protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
} else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
} else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
/**
* Callback after prototype creation.
* <p>The default implementation marks the prototype as not in creation anymore.
*
* @param beanName the name of the prototype that has been created
* @see #isPrototypeCurrentlyInCreation
*/
@SuppressWarnings("unchecked")
protected void afterPrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal instanceof String) {
this.prototypesCurrentlyInCreation.remove();
} else if (curVal instanceof Set) {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.remove(beanName);
if (beanNameSet.isEmpty()) {
this.prototypesCurrentlyInCreation.remove();
}
}
}
当然,这里的钩子仅做了记录,防止循环创建请参见上一篇文章。在读单例缓存失败后直接调用了isPrototypeCurrentlyInCreation(beanName)
。
createBean()
创建实例、初始化封装接口
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
*
* @see #doCreateBean
*/
// 此时已经完成了 bean scope 的判断、bean 循环依赖的判断,现在应该是安心创建 bean 实例的环节了
// 创建 bean 实例、初始化、执行后处理方法
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("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. 确认指向的 bean Class 可以被加载
// 2. 将 BeanDefinition 复制一份,原因与 CopyOnWriteArrayList 相同,防止访问过程中被修改
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
// 理论上加载完成后如果获得结果不为空,mbd 中缓存的 beanClass 应该存在,但是这里没有
// 是有其他线程的影响,所以我们进行复制
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides(); // 将 bean 中要覆盖的方法进行一次统计及修饰
} 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.
// 返回的 bean 实例不一定是目标的实例,可能是一层代理
// TODO: 这里是 AOP 的织入点,现在没看懂,后面可以继续看
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 {
// 根据 beanName,BeanDefinition,入参 进行 bean 实例的创建
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("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);
}
}
此处的思路和之前 Spring 的常用思路一样——先进行一些创建前的校验、准备工作,然后把具体的创建操作委托给对应的具体类进行:
- 先看看
resolveBeforeInstantiation
行不行 - 上面的不行,就委托给
doCreateBean()
来进行
这里做的准备操作主要有以下几种:
- 确认 Bean 对应的 Class 可加载
- 对 BD 中定义的方法覆盖做一下校验,看:
- 配置是否合理
- 如果情况及其简单就顺手打标,减少后面遍历的开销
校验方法覆盖
/**
* Validate and prepare the method overrides defined for this bean.
* Checks for existence of a method with the specified name.
*
* @throws BeanDefinitionValidationException in case of validation failure
*/
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exists.
if (hasMethodOverrides()) {
Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
synchronized (overrides) {
for (MethodOverride mo : overrides) {
prepareMethodOverride(mo);
}
}
}
}
/**
* Validate and prepare the given method override.
* Checks for existence of a method with the specified name,
* marking it as not overloaded if none found.
*
* @param mo the MethodOverride object to validate
* @throws BeanDefinitionValidationException in case of validation failure
*/
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
} else if (count == 1) {
// 只有一个,说明我们要覆盖的方法不需要重写
// Mark override as not overloaded, to avoid the overhead of arg type checking.
mo.setOverloaded(false);
}
}
主要是看一下方法存不存在,如果存在且只有一个就打个标记就好,如果不存在就直接报错,也省的跑一大片创建逻辑了。
doCreateBean()
创建实例、初始化实际逻辑
/**
* 此方法进行 Bean 实例的:
* 1. 创建【通过工厂方法、根据参数指定构造器、默认构造器】
* 2. 实例值填充【解决了依赖问题,也解决了循环依赖问题(单例的)】
* 3. Bean 实例初始化钩子调用
* 4. 检查循环依赖
* 5. 注册 Bean 销毁方法/钩子
*
* @param beanName bean 的Id
* @param mbd BD ,拍平之后的
* @param args 创建所用的入参
* @return bean的一个创建完成的实例,初始化好的那种
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// TODO 此处存疑,需要专门看一下 factoryBeanInstanceCache 的作用及存取
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 1. 创建【通过工厂方法、根据参数指定构造器、默认构造器】
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
// 对 mbd 做一些修饰
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.postProcessed = true; // 标记,此 mbd 完成后处理器的修饰
}
}
// 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.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 把找到的 bean 实例增加到缓存到 ObjectFactory 里去
// 注意,这里使用在本 Factory 中注册的 SmartInstantiationAwareBeanPostProcessor 的方法获得
// 对应的提前引用
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 填充一些 bean 的属性
populateBean(beanName, mbd, instanceWrapper);
// 初始化 bean
// 这里才叫初始化,初始化特指调用初始化和那些钩子方法,其他的包括填充属性,都叫创建实例
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
} else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 提前暴露出去了实例引用,但是我们在后续调用初始化钩子时可能会改变bean的地址,这里要做一下修复和回归
//
// 注意,我们只是完成了创建这个 bean 实例的操作,但是并没有改变 singleton 的注册状态,也就是说我们现在用 getSingleton()获得的
// 还是之前放进去的用于提前暴露的引用
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false); //得到之前提前暴露的实例引用
if (earlySingletonReference != null) { // 刚开始觉得有点冗余,看了后面的实现感觉还是有必要的
if (exposedObject == bean) { // 我们一通操作,没有改变引用地址,说明我们后面的操作能即使同步出去
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { // 我们的一通操作,改变了引用地址【出现了代理或者包裹】
// 1. 是否提前注入原始的 bean 实例来防止循环引用,即使最终这个 bean 会被包裹【否】
// 2. 这个提前暴露出去的 bean 已经被人依赖了
String[] dependentBeans = getDependentBeans(beanName); // 获得依赖这个 bean 的 bean 列表,一个一个修改
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { // 将还没有正式使用的 bean 实例删除
// 删除失败,当时创建这个 bean 是有正经用途的
actualDependentBeans.add(dependentBean);
}
}
// 经过层层筛选,我们发现提前暴露的 bean 里是有正经用途的,不能直接删,那就直接 fail-fast 失败,防止出现隐藏的bug造成更大的损失
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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
// bean 销毁可能还有一些钩子,进行一些注册
// 这里先注册销毁的钩子,再注册创建的钩子,防止出现在注册的间隙提前暴露出去并立刻进行销毁的极端情况
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
// 注册销毁的钩子完成,对外暴露最终的 bean
// 注意:如果是提前暴露的单例 bean ,是从 singletonFactories 的缓存转移到 earlySingletonObjects 就不再动了,此函数只负责创建 bean ,
// 最外面我们是把 createBean 当作 singletonFacotry 传到 getSingleton 里面去的,在完成此方法后,外面的 getSingleton 会完成将 对应的
// bean 实例缓存至 singletonObjects 的。
return exposedObject;
}
思路总体来说还是比较明确的:
1.png其中:
- "解决循环依赖"和"检测解决循环依赖是否成功"两部分直接在
doCreateBean
中直接体现了。思路比较简单,不再赘述。 - "修饰BD"这个我们后面专门介绍一下后处理器相关的操作。
扩展
单例提前暴露为何采用 factory
形式
- 使用函数,更方便定制【站在
DefaultSingletonBeanRegistry
】 - 闭包,保证在调用时尽可能穿出此线程执行的最新的引用【纯个人意淫,感觉执行速度这么快,这种分秒必争的情况应该很少】
问题遗留
resolveBeforeInstantiation
传闻这里是 AOP
织入点,后面回头看。
网友评论