文章目录
https://blog.csdn.net/zxd1435513775/article/details/120935494?spm=1001.2014.3001.5501
Spring源码系列(四)——ConfigurationClassPostProcessor功能解析
https://blog.csdn.net/zxd1435513775/article/details/121113933?spm=1001.2014.3001.5501
Spring源码系列(六)——容器的刷新(下)
在第四篇和第六篇中,都分析到了一个方法,就是getBean()
,这行代码的意思是:从容器中获取Bean
,如果没有,则去创建Bean
。所以在查看Spring
源码时,只要看到这个方法,就要知道是去实例化Bean
了。
这个方法的具体实现位于AbstractBeanFactory
类中,下面就来分析吧。
一、getBean()
下面来看一下这个方法的详细代码:
// 根据name去获取对应的Bean实例
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly){
/**
* 下面这个方法是通过 name 去获取 beanName,这里为什么不使用 name 直接作为 beanName呢?
* 有两个原因:
* 1、name 的值可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身,而非 FactoryBean 实现类所创建的 bean。
* 在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储方式是一致的,即 <beanName, bean>,而 beanName 中是没有 & 这个字符的。
* 所以需要将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例。
* 2、还是别名的问题,转换需要 &beanName
*/
String beanName = transformedBeanName(name);
Object bean;
/**
* 下面这个getSingleton()方法,在上面getBean()的时候也会调用,在Bean初始化的时候会调用
* 为什么需要这么做呢?
* 也就是说Spring容器在Bean初始化的时候先获取这个Bean对象,判断这个对象是否被实例化好了,
* 是不是已经被创建了。普通情况下绝对为空,但有一种情况可能不为空
* 从Spring容器中获取一个Bean,由于Spring中Bean容器是用一个map(singletonObjects)来存储的
* 所以可以理解getSingleton(beanName)等于beanMap.get(beanName)
* 由于getBean()方法会在Spring环境初始化的时候(就是对象被创建的时候调用一次)调用一次
* 还会在Bean初始化的时候再调用一次
* 此处为getSingleton()第一次调用,意思是去缓存里查询该beanName有没有被创建
*/
Object sharedInstance = getSingleton(beanName); // 此方法详解,看下面第二部分
// 此处拿到sharedInstance,不为空,表示已经实例化了,但属性有没有填充不确定
// 在分析FactoryBean的时候,分析了getObjectForBeanInstance()方法,下面我们就分析else的情况
if (sharedInstance != null && args == null) {
/**
* 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。
* 但如果 sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
* bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回即可。
* 毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// 判断是否是原型Bean,如果是原型,不应该在Spring容器初始化的时候创建
// 为什么要直接抛异常呢?因为在refresh()方法中的finishBeanFactoryInitialization()方法中
// 已经对bean进行了判断,BeanDefinition不是抽象的,不是懒加载的,是单列的才会进入执行到此处
// 所以会抛异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 检查Spring工厂中是否存在bean定义
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
} else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
} else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
// 此参数为方法传入进来
if (!typeCheckOnly) {
// 添加到alreadyCreated set集合当中,表示他已经创建过一次
markBeanAsCreated(beanName);
}
try {
// 如果给的bean的定义是有父类的,则通过与父bean合并,返回给定顶级bean的RootBeanDefinition。
// 在使用xml配置Bean时,有个属性parent属性来指定父类
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 再次检查,检查合并后的bean是不是抽象的
checkMergedBeanDefinition(mbd, beanName, args);
// 获取所依赖的bean,保证对当前bean所依赖的bean进行实例化。
// 此处的意思是,被依赖的Bean要先进行实例化
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
// 抛异常代码略
}
registerDependentBean(dep, beanName);
try {
// 又一次调用getBean()方法,此处获取的依赖bean,递归调用,获取即创建
getBean(dep);
} catch (NoSuchBeanDefinitionException ex) {
// 抛异常代码略
}
}
}
// 此处才开始创建Bean,也是此处进行了getSingleton()方法的第二次调用
if (mbd.isSingleton()) {
// 此处为getSingleton()第二次调用,两处调用,形参不一样
// 先执行getSingleton()方法,在该方法中,可以调用lamda表达式
sharedInstance = getSingleton(beanName, () -> {
try {
// 此方法看下面第四部分
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
} finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
// 抛异常代码略
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
// 抛异常代码略
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException ex) {
// 抛异常代码略
}
}
} catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
// 抛异常代码略
}
return convertedBean;
} catch (TypeMismatchException ex) {
// 抛异常代码略
}
}
return (T) bean;
}
二、第一次调用getSingleton()
下面来看下这个方法详细代码:DefaultSingletonBeanRegistry
类中
// 第一处getSingleton()是调用这个方法,根据beanName去singletonObjects中查询是否已经被实例化
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从singletonObjects中获取bean,如果不为空直接返回,不再进行实例化工作
Object singletonObject = this.singletonObjects.get(beanName);
// isSingletonCurrentlyInCreation()方法判断当前beanName是不是正在创建中
// 如果为null并且正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 去earlySingletonObjects中拿,注意这行集合里面存放的对象还没有被填充属性
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果也没拿到,说明还没有创建完成
if (singletonObject == null && allowEarlyReference) {
// 去存放Bean工厂的集合里拿,看看是不是Bean工厂
ObjectFactory<?> singletonFactory =
this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
// 此集合是为了解决循环引用问题
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
public boolean isSingletonCurrentlyInCreation(String beanName) {
// 正在创建的Bean会被放到这个singletonsCurrentlyInCreation集合中
return this.singletonsCurrentlyInCreation.contains(beanName);
}
这里要特别说一下singletonObjects
,earlySingletonObjects
,singletonsCurrentlyInCreation
,singletonFactories
四个作用,很关键!!!
singletonObjects
是个Map<String, Object>
,用于存放完全初始化好的Bean
,从这个Map
中取出的Bean
可以直接使用earlySingletonObjects
是个Map<String, Object>
,用于存放原始的Bean
对象,用于解决Bean
的循环依赖问题,注意:存到里面的对象还没有被填充属性,即还没有完成初始化!!!singletonsCurrentlyInCreation
是个Set<String>
,用于存放正在创建中的Bean
singletonFactories
是个Map<String, ObjectFactory<?>>
,用于存放Bean
工厂对象,也用于解决循环依赖
三、第二次调用getSingleton()
// 第二处getSingleton()是调用这个方法,传进来的第二个参数为lamda表达式
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
// 先从singletonObjects中拿取Bean
Object singletonObject = this.singletonObjects.get(beanName);
// 不为空的话,直接返回
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
// 抛异常代码略
}
// 将beanName添加到singletonsCurrentlyInCreation这样一个set集合中
// 表示beanName对应的bean正在创建中
// 创建之前把beanName放到这个singletonsCurrentlyInCreation集合中
// 在上面第一次调用getSingleto()代码时,有个条件就是当前的beanName是不是在创建中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 分析到此处终于要去创建对象了!!!!!
// 此处的singletonFactory是传进来的,即为lamda表达式,去调用createBean()函数,创建Bean
// 下面要看下第四部分
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException ex) {
// 抛异常代码略
} finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
// 将创建好的Bean放入singletonObjects中
if (newSingleton) {
// 此方法紧接着下面
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 创建好的Bean,放入到singletonObjects
this.singletonObjects.put(beanName, singletonObject);
// 下面这两个集合是什么时候放进去的呢?想想哦~~~~在doCreateBean()方法中
// 从singletonFactories中移除
// 存放 bean工厂对象解决循环依赖
this.singletonFactories.remove(beanName);
// 从earlySingletonObjects中移除
// 存放原始的bean对象用于解决循环依赖,注意:存到里面的对象还没有被填充属性
this.earlySingletonObjects.remove(beanName);
// 创建好的Bean,放入到registeredSingletons
this.registeredSingletons.add(beanName);
}
}
四、createBean()
下面来看一下createBean()
的详细代码:AbstractAutowireCapableBeanFactory
类
// 此方法完成:创建bean实例、填充bean实例、调用后处理器等
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
RootBeanDefinition mbdToUse = mbd;
// 做校验,不重要
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 处理 lookup-method 和 replace-method 配置,Spring 将这两个配置统称为 override method
try {
mbdToUse.prepareMethodOverrides();
} catch (BeanDefinitionValidationException ex) {
// 抛异常略
}
try {
// 在 bean 初始化前应用后置处理,如果后置处理返回的 bean 不为空,则直接返回
// 让 BeanPostProcessors 有机会返回一个代理而不是目标bean实例。
// 注意下这个后置处理器:InstantiationAwareBeanPostProcessor
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
} catch (Throwable ex) {
// 抛异常略
}
try {
// 调用doCreateBean 创建bean
// 请看下面第四部分
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
} catch (Throwable ex) {
// 抛异常略
}
}
五、doCreateBean()
下面来看一下doCreateBean()
的详细代码:AbstractAutowireCapableBeanFactory
类
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 实例化bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
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 实例。
* createBeanInstance()方法看第六小点
*/
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 到此处,Bean实例已经创建了!!!!!
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 后处理器修改合并的bean定义
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable ex) {
// 抛异常略
}
mbd.postProcessed = true;
}
}
// BeanDefinition是单例的,支持循环引用,并且正在创建
// 看到allowCircularReferences这个属性,是不是猜想Spring可以配置是否支持循环引用呢?
boolean earlySingletonExposure = (mbd.isSingleton()
&& this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 将正在创建的Bean放到集合中,此时Bean的属性还没赋值
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 开始初始化Bean对象了,即属性填充
Object exposedObject = bean;
try {
// 属性填充,非常重要!!!!!看第八小点
populateBean(beanName, mbd, instanceWrapper);
// 执行后置处理器,aop就是在这里完成的处理,看第九小点
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable 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()) {
// 抛异常代码略
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch (BeanDefinitionValidationException ex) {
// 抛异常代码略
}
return exposedObject;
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 放到singletonFactories中
this.singletonFactories.put(beanName, singletonFactory);
// 在第一次调用getSingleton()方法是put
// 移除earlySingletonObjects中
this.earlySingletonObjects.remove(beanName);
// 放到registeredSingletons中
this.registeredSingletons.add(beanName);
}
}
}
六、createBeanInstance()
// 使用适当的实例化策略,为指定的bean创建一个新实例:工厂方法、构造函数自动装配,简单实例化。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 获取BeanDefinition所转化的类Class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 检测一个类的访问权限,spring默认情况下对于非public的类是不允许访问的。
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
// 抛异常略
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 如果工厂方法不为空,则通过工厂方法构建 bean 对象
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
/**
* 从Spring的原始注释可以知道这个是一个Shortcut,什么意思呢?
* 当多次构建同一个 bean 时,可以使用这个Shortcut,
* 也就是说不再需要每次推断应该使用哪种方式构造bean
* 比如在多次构建同一个prototype类型的 bean 时,就可以走此处的shortcut
* 这里的 resolved 和 mbd.constructorArgumentsResolved 将会在 bean 第一次实例
* 化的过程中被设置
*/
// 一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器
// 在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,避免再次创建相同bean时再次解析
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
// 已经解析过class的构造器
resolved = true;
// 如果已经解析了构造方法的参数,则必须要通过一个带参构造方法来实例
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
// 已经解析过class的构造器,使用已经解析好的构造器
if (autowireNecessary) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
} else {
// 通过默认的无参构造方法进行
return instantiateBean(beanName, mbd);
}
}
// 由后置处理器决定返回哪些构造方法,决定用哪个构造方法来进行实例化,此方法为选择构造函数的过程
// 需要根据参数解析、确定构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 解析的构造器不为空 || 注入类型为构造函数自动注入 || bean定义中有构造器参数 || 传入参数不为空
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// 使用默认的无参构造方法进行初始化
return instantiateBean(beanName, mbd);
}
createBeanInstance()
方法的代码逻辑如下:
- 如果
Bean
定义中存在InstanceSupplier
,会使用这个回调接口创建对象,应该是3.X以后新加的,3.X的源码中没有 - 根据配置的
factoryMethodName
或factory-mtehod
创建Bean
- 解析构造函数并进行实例化
因为一个类可能有多个构造函数,所以需要根据配置文件中配置的参数或者传入的参数确定最终调用的构造函数,因为判断过程会比较消耗性能,所以Spring
会将解析、确定好的构造函数缓存到BeanDefinition
中的resolvedConstructorOrFactoryMethod
字段中。在下次创建相同Bean
的时候,会直接从RootBeanDefinition
中的属性resolvedConstructorOrFactoryMethod
缓存的值获取,避免再次解析。
七、autowireConstructor()
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
// 创建一个BeanWrapperImpl 前面外部返回的BeanWrapper 其实就是这个BeanWrapperImpl
// 因为BeanWrapper是个接口
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// 如果getBean()中传入的参数不为空,那么就使用传入的参数
// 确定参数值列表
// argsToUse可以有两种办法设置
// 第一种通过beanDefinition设置
// 第二种通过xml设置
if (explicitArgs != null) {
argsToUse = explicitArgs;
} else {
// 否则就需要解析配置文件中的参数
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
// 获取已解析的构造方法,一般不会有,因为构造方法一般会提供一个
// 除非有多个,那么才会存在已经解析完成的构造方法
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// 在缓存中找到了构造器,就继续从缓存中寻找缓存的构造器参数
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 没有缓存的参数,就需要获取配置文件中配置的参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果缓存中没有缓存的参数的话,即argsToResolve不为空,就需要解析配置的参数
if (argsToResolve != null) {
// 解析参数类型,比如将配置的String类型转换成int、boolean等类型
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
// 如果没有缓存,就需要从构造函数开始解析
if (constructorToUse == null) {
// 如果没有已经解析的构造方法,则需要去解析构造方法
// 判断构造方法是否为空,判断是否根据构造方法自动注入
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
// 定义了最小参数个数
// 如果你给构造方法的参数列表给定了具体的值
// 那么这些值的个数就是构造方法参数的个数
int minNrOfArgs;
if (explicitArgs != null) {
// getBean方法传入的参数
minNrOfArgs = explicitArgs.length;
} else {
// 配置文件中的配置的参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
// 用于承载解析后的构造函数参数的值
resolvedValues = new ConstructorArgumentValues();
/**
* 确定构造方法参数数量,假设有如下配置:
* <bean id="scorpios" class="com.scorpios.Scorpios">
* <constructor-arg index="0" value="str1"/>
* <constructor-arg index="1" value="1"/>
* <constructor-arg index="2" value="str2"/>
* </bean>
*
* 在通过spring内部给了一个值得情况那么表示你的构造方法的最小参数个数一定
* minNrOfArgs = 3
*/
// 解析配置文件中的参数,并且返回参数个数
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 如果传入的构造器数组不为空,就使用传入的构造器参数,否则通过反射获取class中定义的构造器
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
// 使用public的构造器或者所有构造器
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
}
// 根据构造方法的访问权限级别和参数数量进行排序
// 怎么排序的呢?
/**
* 有限反问权限,继而参数个数
* 这个自己可以写个测试去看看到底是不是和我说的一样
* 1. public Scorpios(Object o1, Object o2, Object o3)
* 2. public Scorpios(Object o1, Object o2)
* 3. public Scorpios(Object o1)
* 4. protected Scorpios(Integer i, Object o1, Object o2, Object o3)
* 5. protected Scorpios(Integer i, Object o1, Object o2)
* 6. protected Scorpios(Integer i, Object o1)
*/
// 给构造函数排序,public构造函数优先、参数数量降序排序
AutowireUtils.sortConstructors(candidates);
//定义了一个差异变量,这个变量很有分量,后面有注释
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
//循环所有的构造方法
for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
/**
* 这个判断别看只有一行代码理解起来很费劲
* 首先constructorToUse != null这个很好理解
* 前面已经说过首先constructorToUse主要是用来装已经解析过了并且在使用的构造方法
* 只有在它等于空的情况下,才有继续的意义,因为下面如果解析到了一个符合的构造方法
* 就会赋值给这个变量。故而如果这个变量不等于null就不需要再进行解析了,说明spring已经
* 找到一个合适的构造方法,直接使用便可以
* argsToUse.length > paramTypes.length这个代码就相当复杂了
* 首先假设 argsToUse = [1,"luban",obj],需要3个参数的构造函数
* 那么会去匹配到上面的构造方法的1和5
* 由于构造方法1有更高的访问权限,所有选择1,尽管5看起来更加匹配
* 但是我们看2,直接参数个数就不对所以直接忽略
*/
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
break;
}
if (paramTypes.length < minNrOfArgs) {
continue;
}
// 封装解析到的参数信息
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
try {
// 判断是否加了ConstructorProperties注解如果加了则把值取出来
// 可以写个代码测试一下
// @ConstructorProperties(value = {"xxx", "111"})
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
//获取构造方法参数名称列表
/**
* 假设你有一个(String scorpios,Object hua)
* 则paramNames=[scorpios,hua]
*/
paramNames = pnd.getParameterNames(candidate);
}
}
// 获取构造方法参数值列表
/**
* 这个方法比较复杂
* 因为spring只能提供字符串的参数值
* 故而需要进行转换
* argsHolder所包含的值就是转换之后的
*/
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring);
}
} else {
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
/**
* typeDiffWeight 差异量,何谓差异量呢?
* argsHolder.arguments和paramTypes之间的差异
* 每个参数值的类型与构造方法参数列表的类型之间的差异
* 通过这个差异量来衡量或者确定一个合适的构造方法
*
* 值得注意的是constructorToUse=candidate
* 第一次循环一定会typeDiffWeight < minTypeDiffWeight,因为minTypeDiffWeight的值非常大,Integer.MAX_VALUE
* 然后每次循环会把typeDiffWeight赋值给minTypeDiffWeight(minTypeDiffWeight = typeDiffWeight)
* else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight)
* 第一次循环肯定不会进入这个
* 第二次如果进入了这个分支代表什么?
* 代表有两个构造方法都符合我们要求?那么spring就迷茫了
* spring迷茫了怎么办?
* ambiguousConstructors.add(candidate);
* ambiguousConstructors=null 非常重要?
* 为什么重要,因为需要清空
* 这也解释了为什么它找到两个符合要求的方法不直接抛异常的原因
* 如果这个ambiguousConstructors一直存在,spring会在循环外面去exception
*/
// 因为不同构造函数的参数个数相同,而且参数类型为父子关系,所以需要找出类型最符合的一个构造函数
//Spring用一种权重的形式来表示类型差异程度,差异权重越小越优先
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 当前构造函数最为匹配的话,清空先前ambiguousConstructors列表
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
} else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
// 存在相同权重的构造器,将构造器添加到一个ambiguousConstructors列表变量中
// 注意,这时候constructorToUse 指向的仍是第一个匹配的构造函数
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
// 循环结束,没有找打合适的构造方法
if (constructorToUse == null) {
//如果没有匹配的构造函数,抛出异常。略
}
// 如果ambiguousConstructors还存在则异常?为什么会在上面方法中直接exception?
// 上面注释当中有说明
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
// 如果存在多个构造函数匹配程度相同,并且BeanDefinition中设置isLenientConstructorResolution为false(默认值为true),
// 表示构造器创建为严格模式的话,会抛出异常。异常代码略
}
// 这一步就是将解析好的构造函数放入缓存resolvedConstructorOrFactoryMethod,如果需要的话也会缓存参数
// 并设置constructorArgumentsResolved为true,表示已经解析过构造函数
if (explicitArgs == null) {
/*
* 缓存相关信息,比如:
* 1. 已解析出的构造方法对象 resolvedConstructorOrFactoryMethod
* 2. 构造方法参数列表是否已解析标志 constructorArgumentsResolved
* 3. 参数值列表 resolvedConstructorArguments 或 preparedConstructorArguments
* 这些信息可用在其他地方,用于进行快捷判断
*/
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
try {
// 使用反射创建实例 lookup-method 通过CGLIB增强bean实例
final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor<?> ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
beanFactory.getAccessControlContext());
} else {
beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
bw.setBeanInstance(beanInstance);
return bw;
}
}
autowireConstructor()
这个方法代码非常长,总体的功能逻辑如下
- 确定参数
- 如果调用
getBean()
方法时传入的参数不为空,则可以直接使用传入的参数 - 再尝试从缓存中获取参数
- 否则,需要解析
<bean>
节点配置的构造器参数
- 如果调用
- 确定构造函数。根据第一步中确定下来的参数,接下来的任务就是根据参数的个数、类型来确定最终调用的构造函数。首先是根据参数个数匹配,把所有构造函数根据参数个数升序排序,再去筛选参数个数匹配的构造函数,因为配置文件中可以通过参数位置索引,也可以通过参数名称来设定参数值,如
<constructor name="title">
,所以还需要解析参数的名称。最后,根据解析好的参数名称、参数类型、实际参数就可以确定构造函数,并且将参数转换成对应的类型 - 根据确定的构造函数转换成对应的参数类型
- 构造函数不确定性的验证。因为有一些构造函数的参数类型为父子关系,所以
Spring
会做一次验证 - 如果条件符合(传入参数为空),将解析好的构造函数、参数放入缓存
- 根据实例化策略将构造函数、参数实例化
Bean
这个方法就是为了找到最合适的构造函数来实例化Bean,需要来确定构造函数的参数个数。
八、populateBean()
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
// 抛异常略
} else {
// 空对象直接返回
return;
}
}
// 给InstantiationAwareBeanPostProcessors最后一次机会在属性注入前修改Bean的属性值
// 具体通过调用postProcessAfterInstantiation方法,如果调用返回false,表示不必继续进行依赖注入,直接返回
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// pvs是一个MutablePropertyValues实例,里面实现了PropertyValues接口,提供属性的读写操作实现,同时可以通过调用构造函数实现深拷贝
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 根据Bean配置的依赖注入方式完成注入,默认是0,即不走以下逻辑,所有的依赖注入都需要在xml文件中有显式的配置
// 如果设置了相关的依赖装配方式,会遍历Bean中的属性,根据类型或名称来完成相应注入,无需额外配置
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 深拷贝当前已有的配置
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 根据名称进行注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 根据类型进行注入
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
// 结合注入后的配置,覆盖当前配置
pvs = newPvs;
}
// 容器是否注册了InstantiationAwareBeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否进行依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 过滤出所有需要进行依赖检查的属性编辑器
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 如果有相关的后置处理器,进行后置处理
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
// 检查是否满足相关依赖关系,对应的depends-on属性,需要确保所有依赖的Bean先完成初始化
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
if (pvs != null) {
// 将pvs上所有的属性填充到BeanWrapper对应的Bean实例中,注意到这一步,TestBean的student属性还是RuntimeBeanReference,即还未解析实际的Student实例
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
Spring的装配问题:
public static final int AUTOWIRE_NO = 0;
public static final int AUTOWIRE_BY_NAME = 1;
public static final int AUTOWIRE_BY_TYPE = 2;
public static final int AUTOWIRE_CONSTRUCTOR = 3;Spring默认的装配类型是AUTOWIRE_NO,表示不默认装配,除非你在代码中手动添加@Autowired、@Resouce等注解手动注入
AUTOWIRE_BY_TYPE表示为按类型装配,在实例化类的时候是根据属性是否具有set方法,如果有,则进行装配
九、initializeBean()
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 权限校验
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
} else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 调用BeanPostProcessor的postProcessBeforeInitialization()方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 调用初始化方法,先执行实现InitializingBean接口的方法,再执行自定义的init-method方法
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {
// 抛异常略
}
if (mbd == null || !mbd.isSynthetic()) {
// 调用BeanPostProcessor的postProcessAfterInitialization()方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
十. invokeInitMethods()
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 是不是实现了InitializingBean
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
// 调用afterPropertiesSet()方法
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
// 是不是有自定义的init-method方法
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 执行自定义的init-method方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
十一、小结
以上的getBea()
方法终于分析完了,其中doCreateBean()
方法比较重要吧,要重点看一下,autowireConstructor()
方法比较难理解,但知道它的作用是什么就好了.
下面来用一张图总结一下这个过程吧。
上图中,红蓝色的框表示的循环依赖的问题,此处简单描述一下。
X
和Y
相互依赖,先实例化X
,在实例化X
的过程中会发现X
依赖了Y
,于是就去实例化Y
,就是图中的红色虚线
在实例化Y
的过程中,发现Y
又依赖于X
,但此时的X
正在创建,被保存在singletonFactories
中,所以就把singletonFactories
中的X
赋值给了Y
,这样Y
的依赖就解决了,所以Y
的实例化就结束了,就会把Y
正常返回
下面就继续实例化X
的流程了。
补充:如何解决循环依赖?是否支持循环依赖?
在Spring
中,默认开启循环依赖,有一个参数:allowCircularReferences = true;
Spring
在解决循环依赖时,使用了三级缓存策略:
第一级缓存:也较单例池,singletonObjects
,存放已经经历了完整生命周期的Bean
对象;
第二级缓存:earlySingletonObjects
,存放早期暴露出来的Bean
对象,Bean
的生命周期未结束(属性还未填充完)
第三级缓存:singletonFactories
,存放可以生成Bean
的工厂
假设A
、B
具有循环依赖,先创建了A
:
A
创建过程中需要B
,于是A
将自己放到三级缓存中,去实例化B
B
实例化的时候发现需要A
,于是B
先去查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A
,然后把三级缓存里面的这个A
放到二级缓存里面,并删除三级缓存里面的A
B
顺利初始化完毕后,将自己放到一级缓存里面(此时B
里面的A
依然是创建中状态),然后回来接着创建A
,此时B
已经创建结束,直接从一级缓存中拿到B
,然后完成创建,并将A
自己放到一级缓存里面
可以结合上图中,红蓝部分理解。