Spring源码-创建单例bean的过程
一.简介
对于实例化好的单例bean,getBean(String)方法并不会再一次去创建,而是从缓存中获取。如果某个bean还未实例化,这个时候就无法命中缓存,此时,就要根据bean的配置信息去创建这个bean了。相较于getBean(String)方法的实现逻辑,创建bean的方法create(String,RootBeanDefinition,Object[])及所调用的方法逻辑更加复杂一些,本次就先从大体上分析createBean方法逻辑。
二.源码分析
2.1 创建bean实例的入口
我们首先要知道createBean方法在哪些被调用,如下:
public T doGetBean(...) {
// 省略不相关代码
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 省略不相关代码
}
上面是doGetBean方法的代码片段,从中可以发现调用了createBean方法。createBean方法被匿名工厂类的getObject方法包裹,但是这个匿名工厂类并未直接调用getObject方法,而是将自身作为参数传递给getSingleton(String,ObjectFactory)方法。getSingleton这个方法实现我们之前讲过,逻辑如下:
1.先从singletonObjects集合获取bean实例,若不为空,直接返回
2.若为空,进入创建bean实例阶段。先将beanName添加到singletonCurrentlyInCreation
3.通过getObject方法调用createBean方法创建bean实例
4.将beanName从singletonCurrentlyInCreation集合中移除
5.将<beanName,singletonObject>映射缓存到singletonObjects集合中
从上面的分析中,了解可createBean在什么时候和地方被调用,下来需要了解createBean做了什么事情。
2.2 createBean
源码分析如下:
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 解析 bean 的类型
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
// 处理 lookup-method 和 replace-method 配置,Spring 将这两个配置统称为 override method
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 在 bean 初始化前应用后置处理,如果后置处理返回的 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);
}
// 调用 doCreateBean 创建 bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
执行流程如下:
1.根据设置的class属性或者根据className来解析class
2.对override属性进行标记及验证。在Spring配置中是存着lookup-method和replace-method的,而这两个配置的加载就是讲配置同一存放在BeanDefinition中的methodOverrides属性里,而这个函数的操作其实也就是针对这两个配置的。
3.应用初始化前的后处理器,解析指定bean是否存在初始化的短路操作。
4.创建bean。
2.3 验证和准备override方法
在Spring配置中是存着lookup-method和replace-method的,而这两个配置的加载就是讲配置同一存放在BeanDefinition中的methodOverrides属性里,这两个功能实现原理其实是在bean实例化的时候如果检测到methodOverrides属性里,会动态地为当前bean生成代理并使用对应的拦截器对bean做增强处理,相关逻辑实现在bean实例化会讲到。
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
MethodOverrides methodOverrides = getMethodOverrides();
if (!methodOverrides.isEmpty()) {
Set<MethodOverride> overrides = methodOverrides.getOverrides();
synchronized (overrides) {
// 循环处理每个 MethodOverride 对象
for (MethodOverride mo : overrides) {
prepareMethodOverride(mo);
}
}
}
}
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
// 获取方法名为 mo.getMethodName() 的方法数量,当方法重载时,count 的值就会大于1
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
// count = 0,表明根据方法名未找到相应的方法,此时抛出异常
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
// 若 count = 1,表明仅存在已方法名为 mo.getMethodName(),这意味着方法不存在重载
else if (count == 1) {
// 方法不存在重载,则将 overloaded 成员变量设为 false
mo.setOverloaded(false);
}
}
上面的源码中,prepareMethodOverrides方法循环调用了prepareMethodOverride 方法,并没其他的太多逻辑。主要准备工作都是在 prepareMethodOverride 方法中进行的。prepareMethodOverride 这个方法主要用于获取指定方法的方法数量 count,并根据 count 的值进行相应的处理。count = 0 时,表明方法不存在,此时抛出异常。count = 1 时,设置 MethodOverride 对象的overloaded成员变量为 false。这样做的目的在于,提前标注名称mo.getMethodName的方法不存在重载,在使用 CGLIB 增强阶段就不需要进行校验,直接找到某个方法进行增强即可。
2.4 实例化的前置处理
用户通过实现 BeanPostProcessor 接口,并将实现类配置到 Spring 的配置文件中(或者使用注解),即可在 bean 初始化前后进行自定义操作。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// 检测是否解析过,mbd.beforeInstantiationResolved 的值在下面的代码中会被设置
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
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
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
2.4.1 实例化前的后处理器应用
bean的实例化前调用,也就是将AbstractBeanDefinition转换为BeanWrapper前的处理。给子类一个修改BeanDefinition机会,也就是说当程序经过这个方法后,bean可能不是我们认为的bean了,而是或许称为了一个经过处理代理的bean,也可能是通过cglib生成的也可能是通过其他技术生成的。
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// InstantiationAwareBeanPostProcessor 一般在 Spring 框架内部使用,不建议用户直接使用
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// bean 初始化前置处理
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
2.4.2 实例化后的后处理器应用
Spring中的规则是在bean的初始化后尽可能保证将注册的后处理器的postProcessAfterInitialization方法应用到该bean中,因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后置处理器postProcessAfterInitialization。
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
// bean 初始化后置处理
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
2.5 调用 doCreateBean 方法创建 bean
当经历过后resolveBeforeInstantiation方法之后,程序有两个选择,如果创建了代理或者重写了InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法并在方法的postBeforeInstantiation中改变了bean,则直接返回就行,否则就要惊醒常规bean的创建,常规bean的创建就是doCreateBean中完成的。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
/*
* BeanWrapper 是一个基础接口,由接口名可看出这个接口的实现类用于包裹 bean 实例。
* 通过 BeanWrapper 的实现类可以方便的设置/获取 bean 实例的属性
*/
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 从缓存中获取 BeanWrapper,并清理相关记录
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
/*
* 创建 bean 实例,并将实例包裹在 BeanWrapper 实现类对象中返回。createBeanInstance
* 中包含三种创建 bean 实例的方式:
* 1. 通过工厂方法创建 bean 实例
* 2. 通过构造方法自动注入(autowire by constructor)的方式创建 bean 实例
* 3. 通过无参构造方法方法创建 bean 实例
*
* 若 bean 的配置信息中配置了 lookup-method 和 replace-method,则会使用 CGLIB
* 增强 bean 实例。后面会解析到
*/
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 此处的 bean 可以认为是一个原始的 bean 实例,暂未填充属性
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
// 这里又遇到后置处理了,此处的后置处理是用于处理已“合并的 BeanDefinition”。
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;
}
}
/*
* earlySingletonExposure 是一个重要的变量,这里要说明一下。该变量用于表示是否提前暴露
* 单例 bean,用于解决循环依赖。earlySingletonExposure 由三个条件综合而成,如下:
* 条件1:mbd.isSingleton() - 表示 bean 是否是单例类型
* 条件2:allowCircularReferences - 是否允许循环依赖
* 条件3:isSingletonCurrentlyInCreation(beanName) - 当前 bean 是否处于创建的状态中
*
* earlySingletonExposure = 条件1 && 条件2 && 条件3
* = 单例 && 是否允许循环依赖 && 是否存于创建状态中。
*/
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");
}
// 添加工厂对象到 singletonFactories 缓存中
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
// 获取早期 bean 的引用,如果 bean 中的方法被 AOP 切点所匹配到,此时 AOP 相关逻辑会介入
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
Object exposedObject = bean;
try {
// 向 bean 实例中填充属性,populateBean 方法也是一个很重要的方法,后面会专门写文章分析
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
/*
* 进行余下的初始化工作,详细如下:
* 1. 判断 bean 是否实现了 BeanNameAware、BeanFactoryAware、
* BeanClassLoaderAware 等接口,并执行接口方法
* 2. 应用 bean 初始化前置操作
* 3. 如果 bean 实现了 InitializingBean 接口,则执行 afterPropertiesSet
* 方法。如果用户配置了 init-method,则调用相关方法执行自定义初始化逻辑
* 4. 应用 bean 初始化后置操作
*
* 另外,AOP 相关逻辑也会在该方法中织入切面逻辑,此时的 exposedObject 就变成了
* 一个代理对象了
*/
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);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 若 initializeBean 方法未改变 exposedObject 的引用,则此处的条件为 true。
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
// 注册销毁逻辑
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
方法的执行流程如下:
1.如果是单例则需要清理缓存
2.实例化bean,将BeanDefinition转换为BeanWrapper。这里的转换有:
- 如果存在工厂方法则使用工厂方法进行初始化
- 一个类有多个构造函数,每个构造函数都有不同的参数,所以需要参数锁定构造函数并进行初始化
- 如果既不存在工厂方法也不存在带有参数的构造函数,则使用默认的构造函数进行bean的实例化
3.应用 MergedBeanDefinitionPostProcessor 后置处理器相关逻辑
4.根据条件决定是否提前暴露 bean 的早期引用(early reference),用于处理循环依赖问题
5.属性填充,将所有属性填充到bean的实例中
6.循环依赖检查,在这个步骤里会检测已经加载的bean是否已经出现了依赖循环,并判断是否需要抛出异常。
7.注册DisposableBean,以便于销毁时候调用
8.完成创建并返回
参考:Spring IOC 容器源码分析 - 创建单例 bean 的过程
《Spring源码深度解析》
上一篇: Java实现排列组合