Spring版本:
<version>5.2.1.RELEASE</version>
目录
上一篇:17-Spring源码解析之Bean的生命周期(2)——【getSingleton】和【createBean】
上一篇我们讲到了getSingleton
方法调用createBean
方法来准备创建Bean
。通过上一篇文章,我们也了解到,createBean
方法首先调用resolveBeforeInstantiation
方法,resolveBeforeInstantiation
方法的返回值决定程序的后续执行步骤。即在执行resolveBeforeInstantiation
后,程序有以下两个选择:
- 如果创建了代理或者重写了
InstantiationAwareBeanPostProcessor
的postProcessBeforeInstantiation
方法并在方法postProcessBeforeInstantiation
中改变了Bean
,则直接返回。 - 如果没有改变
Bean
,就需要进行常规Bean
的创建。
而常规Bean
的创建就是createBean
调用doCreateBean
实现的。
一、doCreateBean
创建Bean
我们跟踪了这么多Spring
的代码,或多或少也发现了一个规律:一个真正干活的函数其实是以do
开头的,比如doCreateBean
,而给我们错觉的函数,比如getBean
,其实是从全局角度去做一些统筹工作。
废话不多说,直接上doCreateBean
源码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
//-------------------------------------------------【功能一】-------------------------------------------------
// 如果是单例,则需要首先清除缓存,然后再开始创建
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
//-------------------------------------------------【功能二】--二节 详细讲解-----------------------------------------------
if (instanceWrapper == null) {
// 实例化Bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//-------------------------------------------------【功能三】--1.1 详细讲解-----------------------------------------------
// 第二个BeanPostProcessor
// @Autowired 和 @Value注解就是再这里被解析的
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;
}
}
//-------------------------------------------------【功能四】--1.2 详细讲解-----------------------------------------------
// 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 && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
//-------------------------------------------------【功能七】---------------------------------------------------
// 解决循环依赖问题
if (earlySingletonExposure) {
// 从缓存中获取当前beanName,因为现在当前bean还没有将自己放到缓存里,
// 如果现在可以从缓存中获取到该bean,那就说明一定是其他的bean依赖了这个bean
Object earlySingletonReference = getSingleton(beanName, false);
// 只有在检测到循环依赖的情况下earlySingletonReference才不为空
if (earlySingletonReference != null) {
// 如果exposedObject 没有在初始化方法中被改变,即没有被增强
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);
}
}
// 因为beanc创建后其所依赖的bean一定是已经创建的,
// actualDependentBeans不为空,说明当前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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
//-------------------------------------------------【功能八】--注册DisposableBean---------------------------------------
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
从上面代码可以看出,doCreateBean
方法包含8个功能。
先不谈Spring
是如何创建对象的,我们想一下如果我们自己创建一个对象的时候,程序都是怎么执行的,首先调用构造器,然后调用setXXX()
方法设置属性值,然后就可以开始使用了。
实际上Spring
也是按照这个思路去创建Bean
实例的。那我们就来看看他每一步都做了什么并且是怎么做的吧。
1.1 【功能三】applyMergedBeanDefinitionPostProcessors
方法
这是我们在Spring
创建Bean
的过程中第二次遇到Spring
执行我们的扩展接口了!我们看一下applyMergedBeanDefinitionPostProcessors
方法的实现。
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
我们可以看出,该方法会执行MergedBeanDefinitionPostProcessor
类型的后置处理器的postProcessMergedBeanDefinition
方法。
我们看一下哪些BeanPostProcessor
是这个类型的:
看到了两个熟悉的类:
-
AutowiredAnnotationBeanPostProcessor
- 解析
@Autowire
和@Value
注解 - 解析
@Inject
注解
- 解析
-
CommonAnnotationBeanPostProcessor
- 解析
javax.annotation
包下的JSR-250
注解:@Resource
注解 - 解析
@PostConstruct
注解 和@PreDestroy
注解
- 解析
说明,程序中的@Autowire
、@Value
、@Inject
、@Resource
、@PostConstruct
、 @PreDestroy
注解在这里被解析。这里不详细讲解,这里只是对这个后置处理器有一个印象,我们还是要先看一下整个函数的概要思路,之后的文章会举一个简单的例子讲解Spring
是如何解析以上注解的。
1.2 【功能四】依赖处理
doCreateBean
的【功能四】是为了处理依赖的。因为该处代码判断条件比较多,在下面又贴出来一遍方便讲解
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));
}
我们可以看到earlySingletonExposure
的值由3个条件决定。
earlySingletonExposure
:从字面的意思理解就是提早曝光的单例。下面我们看一下哪三个条件影响这个值- 【条件一】
mbd.isSingleton()
:此RootBeanDefinition
是否是单例 - 【条件二】
this.allowCircularReferences
:beanFactory
是否允许循环依赖。默认:允许(true
) - 【条件三】
isSingletonCurrentlyInCreation
:该Bean
是否在创建中。在Spring
中,会有一个专门的属性默认为DefaultSingletonBeanRegistry
的singletonCurrentlyInCreation
来记录Bean
的加载状态。- 在
Bean
开始创建前会将beanName
记录在属性中(详见:上篇文章:1.1getSingleton
的【功能二】beforeSingletonCreation方法) - 在
Bean
创建结束后会将BeanName
从属性中移除(详见:上篇文章:1.2getSingleton
的【功能四】afterSingletonCreation方法)
- 在
- 【条件一】
经过以上分析,我们了解了变量earlySingletonExposure
是是否单例、是否允许循环依赖、是否对应的Bean
正在创建的条件的综合。
当这三个条件都满足时会执行addSingletonFactory
方法,那么我们要知道将这个刚实例化完还没有赋属性值的Bean
提早暴露到beanFactory
的作用又是什么呢?这里就涉及到了循环依赖问题。 Spring
中的依赖注入和循环依赖问题是一个比较重要的问题,后续会有一篇单独的文章介绍这两个问题,这里先不详细介绍。 先有一个印象:这里是为了处理依赖而增加的操作。
二、 【功能二】createBeanInstance
创建Bean
实例
doCreateBean
是通过调用createBeanInstance
来实现创建Bean
实例功能的,然后他把创建好的实例放到了BeanWrapper
类型的对象中。想一想,创建实例是什么?创建实例就是:调用构造方法啊!
但是我们在仔细看他是如何调用构造方法之前,我们需要了解一下BeanWrapper
类型是什么,为什么把返回值放到BeanWrapper
类型的对象中。
2.1 BeanWrapper
接口
public interface BeanWrapper extends ConfigurablePropertyAccessor {
void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);
int getAutoGrowCollectionLimit();
Object getWrappedInstance();
Class<?> getWrappedClass();
PropertyDescriptor[] getPropertyDescriptors();
PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
}
这个接口的方法不是很多,我们可以通过看他的注解知道该类主要的一个功能就是:
提供分析和操作标准JavaBean
的操作:获取和设置属性值(单独或批量),获取属性描述符以及查询属性的可读性/可写性的能力
Spring
对该接口的唯一实现类是:BeanWrapperImpl
,这个类的实现很多都是在调用cache
有关的类获取对应的值,有兴趣的同学可以自行查看源码,这里就不详细介绍了。
下面我们就开始执行createBeanInstance
方法,这个方法我们就记住他相当于new
一个对象的时候,执行的构造函数方法。
2.2 createBeanInstance
方法
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 解析Class,实际上在createBean的时候已经解析过一次class了,这为什么又解析了一次。。
// 我还没搞明白,待研究??
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// //确保class不为空,并且访问权限为public 因此Spring创建不了Class访问权限不是public的,
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);
}
//-------------------------------------------------【功能一】------------------------------------------
// 如果工厂方法不为空则使用工厂方法初始化策略
// 若在配置类中利用@Bean的方式注册Bean,那么在创建该Bean的时候使用就是工厂方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
//-------------------------------------------------【功能二】------------------------------------------
// 如果传递进来的构造函数的参数为null
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 判断缓存中是否已经解析过构造函数
// 如果解析过则将当前方法的解析标志字段设置为true
// resolvedConstructorOrFactoryMethod属性 : 用于缓存已解析构造函数或工厂方法的包可见字段
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
// constructorArgumentsResolved属性:将构造函数参数标记为已解析的包可见字段。
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
//-------------------------------------------------【功能三】------------------------------------------
// 如果已经解析过则使用解析好的构造函数方法
if (resolved) {
if (autowireNecessary) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 使用默认构造函数构造
return instantiateBean(beanName, mbd);
}
}
//-------------------------------------------------【功能四】------------------------------------------
// Candidate constructors for autowiring?
// determineConstructorsFromBeanPostProcessors:查找Bean的所有有参的构造函数
// 并返回一个构造函数用于创建Bean
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);
}
//----------------------------------【功能六】-2.2.1 详细讲解--------------------------------------
// 使用无参构造函数构造
return instantiateBean(beanName, mbd);
}
以上可以看出createBeanInstance
方法包含了6个功能,实际上就是根据不同的策略来实例化Bean
实例。
其中有三种策略:(本文只讲解使用注解的情况下遇到的三种策略)
-
【策略一】:
instantiateUsingFactoryMethod
工厂方法策略- 若在配置类中通过
@Bean
注解来注册Bean
- 若在配置类中通过
-
【策略二】:
determineConstructorsFromBeanPostProcessors
方法解析构造函数后通过autowireConstructor
构造函数注入策略,项目中不常用。- 若在类中的构造函数上标注了
@Autowired
属性会走这个方法,且该类是通过@Service
、@Repository
注册到容器中的
- 若在类中的构造函数上标注了
-
【策略三】:
instantiateBean
- 使用无参的构造函数
我们知道,当我们的项目通过注解装配的方式来构建时,我们是不会写构造函数的,我们只是在相应的类中写需要使用的属性,而这些属性赋值任务是通过依赖注入的方式实现的。因此,在这一步,我们只分析项目中会走到的方法instantiateBean
。
2.2.1 instantiateBean
方法
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
//-------------------------------------------------核 心------------------------------------------
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
实例化策略:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// 如果有需要覆盖或者动态替换的方法,则需要使用CGLIB进行动态代理
// 这种情况是:用户使用了 replace 或者 lookup 的配置方法
if (!bd.hasMethodOverrides()) {
// 进入这里说明使用的是我们自己的无参构造器
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
// 获取无参构造器
constructorToUse = clazz.getDeclaredConstructor();
}
// resolvedConstructorOrFactoryMethod :缓存已解析构造函数
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 执行无参构造器
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
调用BeanUtils.instantiateClass(constructorToUse);
来执行无参构造器
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
return KotlinDelegate.instantiateClass(ctor, args);
}
else {
Class<?>[] parameterTypes = ctor.getParameterTypes();
Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
Object[] argsWithDefaultValues = new Object[args.length];
for (int i = 0 ; i < args.length; i++) {
if (args[i] == null) {
Class<?> parameterType = parameterTypes[i];
argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
}
else {
argsWithDefaultValues[i] = args[i];
}
}
//--------------------------------执行我们自己类的无参构造方法-----------------------------------------
return ctor.newInstance(argsWithDefaultValues);
}
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
以上,就完成了创建实例Bean
的过程,其中有一些项目中不会走到的方法,这里就没有详细讲解,比如如果解析有参构造器(determineConstructorsFromBeanPostProcessors
),如何执行有参构造器(autowireConstructor
)
三、总结
- 【
doCreateBean
】功能- 【功能一】 如果是单例则需要首先清除缓存,然后开始创建,防止在并发时同时创建
- 【功能二】 调用
createBeanInstance
方法实例化Bean
,将BeanDefinition
转换为BeanWrapper
- 【功能三】 调用
applyMergedBeanDefinitionPostProcessors
方法来做实例化Bean
后利用AutowiredAnnotationBeanPostProcessor
类型的后置处理器解析@Autowired
注解。 - 【功能四】依赖处理
- 【功能五】
populateBea
属性填充 - 【功能六】
initializeBean
初始化 - 【功能七】循环依赖检查
- 【功能八】注册
DisposableBean
- 【
createBeanInstance
】功能:根据不同的情况执行不同的实例化策略-
【策略一】:
instantiateUsingFactoryMethod
工厂方法策略- 若在配置类中通过
@Bean
注解来注册Bean
- 若在配置类中通过
-
【策略二】:
determineConstructorsFromBeanPostProcessors
方法解析构造函数后通过autowireConstructor
构造函数注入策略,项目中不常用。- 若在类中的构造函数上标注了
@Autowired
属性会走这个方法,且该类是通过@Service
、@Repository
注册到容器中的
- 若在类中的构造函数上标注了
-
【策略三】:
instantiateBean
- 使用无参的构造函数
-
doCreateBean
方法中还有两个比较重要的方法:
-
populateBean
属性注入- 这里也会涉及循环依赖的情况,因此是一个比较重要的话题,在依赖注入篇会详细讲解,这里不再详述,只是记得在实例化
Bean
(createBeanInstance
)之后,初始化Bean
(initializeBean
)之前会执行属性注入
- 这里也会涉及循环依赖的情况,因此是一个比较重要的话题,在依赖注入篇会详细讲解,这里不再详述,只是记得在实例化
-
initializeBean
初始化Spring
给我们留了很多扩展点,其中在初始化前后就留了3个扩展点,非常重要。
下一篇我们继续讲解initializeBean
方法的实现。