Bean loading (4)
The previous article mainly explained the issues related to Spring's circular dependencies. This article continues to explain the creation of beans on the bean loading process.
Create Bean
We first enter the createBean method.
In the previous article, we said that after going through the resolveBeforeInstantiation method, the program will have two choices. If a proxy is created or the postProcessBeforeInstantiation method in InstantiationAwareBeanPostProcessor is rewritten and the bean is changed in the method postProcessBeforeInstantiation, it will return directly, otherwise the routine will be performed. bean creation.
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//给BeanPostProcessors一个机会来返回代理用于替代真正的实例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
The creation of regular beans is done in doCreateBean.
//代码(1)
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
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) {
// 将解析类型设置为beanType
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 这里主要是 MergedBeanDefinitionPostProcessor 对@Autowire,@Value这些注解进行处理
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//是否需要提前曝光,单例&&允许循环依赖&&当前bean正在创建中,检测循环依赖
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");
}
// 为避免后期循环依赖,可以在 bean 初始化完成前将创建实例的 objectFactory加入缓存
// 对bean 再一次依赖引用,主要应用SmartInstantiationAwareBeanPostProcessor
// 其中我们熟悉的AOP就是在这里将advice 动态织入,若没有直接返回bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//对bean进行填充,比如设置属性,其中可能存在依赖其他bean,则会递归初始化依赖的bean
populateBean(beanName, mbd, instanceWrapper);
// 进一步初始化Bean
// 注入 Aware 相关的对象
// 调用 后置处理器 BeanPostProcessor 里面的postProcessBeforeInitialization方法
// 调用 InitializingBean中的的 afterPropertiesSet()
// 调用 init-method,调用相应的init方法
// 调用 后置处理器 BeanPostProcessor 里面的调用实现的postProcessAfterInitialization方法
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);
// 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);
}
}
/**
因为 bean 创建后其所依赖的bean一定是已经创建,
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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
// 注册到 disposableBeans 里面,以便在销毁bean 的时候 可以运行指定的相关业务
registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
This method is relatively long, so let's sort out the ideas first.
- If it is a singleton, you need to clear the cache first
Instantiate bean, convert BeanDefinition to BeanWrapper
Conversion is a relatively complex process, roughly as follows:
- If a factory method exists, use the factory method to initialize
- A class has multiple constructors, so the constructors need to be locked and initialized according to the parameters
- If neither a factory method nor a constructor with parameters exists, use the default no-argument constructor for initialization
- Application of mergedBeanDefinitionPostProcessor. The processing after the bean is merged, the Autowired annotation is the pre-parsing implemented by this method
- Dependency handling. Dealing with circular dependencies, as mentioned in the previous chapter, is to put the instance that needs to be injected into the ObjectFactory in the cache to solve it
- Property fill. Populate all properties into the bean instance
- Circular dependency checking. As I said before, Spring can only solve circular dependencies of singletons. For beans with other scope attributes, Spring will detect whether there are circular dependencies in this step, and throw an exception if they exist.
- Register DisposableBean. If destroy-method is configured, it needs to be registered here to be called when destroyed
- complete creation and return
It can be seen that the steps are very complicated, and we will understand it step by step.
Create an instance of the bean
Let's start with the createBeanInstance method.
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
//确保bean已经被解析
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 如果beanClass 不是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());
}
// 如果存在,就返回一个 callback回调函数,在 obtainFromSupplier 方法里调用对应的具体方法 ,并转换成 BeanWrapper 类型
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果工厂方法不为空则使用工厂方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
//一个类有多个构造函数,每个构造函数都有不同的参数,所以调用前需要先根据参数锁定构造函数或对应的工厂方法
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
//如果已经解析过则使用解析好的构造函数,不需要再次指定
if (resolved) {
if (autowireNecessary) {
//构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
} else {
//使用默认的构造函数
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
//需要根据参数解析构造函数
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?
// 如果上面没有解析好对应的构造函数, 这里看看有没有指定构造函数
/**
具体里面其实 是 SmartInstantiationAwareBeanPostProcessor , 这个类 继承了
InstantiationAwareBeanPostProcessor, 调用里面的determineCandidateConstructors方法来确认有没有指定的构造函数
*/
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
//使用默认的构造函数
return instantiateBean(beanName, mbd);
}
Although the details of instantiation in the code are complex, we can sort out the following logic:
- If the factoryMethodName attribute exists in the RootBeanDefinition, or the factory-method is configured in the configuration file, the
instantiateUsingFactoryMethod(beanName, mbd, args)
method will be called to generate an instance of the bean according to the configuration in the RootBeanDefinition. - Parse the constructor and initialize the constructor. Spring determines which constructor to use for instantiation based on the parameters and types. Since the judgment consumes performance, the caching mechanism is adopted. If it has been parsed, it does not need to be parsed repeatedly, but is taken from the cached value of the attribute resolvedConstructorOrFactoryMethod in the RootBeanDefinition. Otherwise, it needs to be parsed and the parsed result is added to resolvedConstructorOrFactoryMethod.
Parse autowireConstructor
method
/**
* beanName: Bean的名称
* mbd: 该bean的BeanDefinition
* chosenCtors: 该类的构造器数组
* explicitArgs:这个方法时通过getBean方法过来的,那么既然是getBea过来的,那么在我们getBean的时候除了传入beanName/beanClass以外,还可以传入其他参数,如果传入了其他参数,那么Spring
* 则认为这些参数是构造器初始化对象时的构造方法参数列表,而这个其他参数就是此时的explicitArgs.
*/
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
/**
* 初始化BeanWrapper
* */
this.beanFactory.initBeanWrapper(bw);
/**
* constructorToUse是我们实际上使用的构造器
* */
Constructor<?> constructorToUse = null;
/**
* argsHolderToUse用来存储用到的构造器的参数,下面的argsToUse的值也是从这个argsHolderToUse中取出来的
*/
ArgumentsHolder argsHolderToUse = null;
/**
* 构造方法中使用到的参数列表实际的值
* */
Object[] argsToUse = null;
/**
* 总结一下这个if和else:
* 1、判断是否传入构造参数值列表,如果传入则赋值
* 2、没有传入则从缓存中去取
* */
/**
* 如果我们getBean的时候传入了参数,那么Spring就认为我们希望按照指定的构造参数列表去寻找构造器并实例化对象.
* 那么这里如果不为空则实际上需要使用的构造方法参数列表值就已经确定了
* */
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
/**
* 这里干的事情很简单,如果这个bean是原型的,那么说明此方法肯定进入过,那么也肯定找到过合适的构造方法和构造参数值列表,在找到合适的构造方法和构造参数值列表后会加入到缓存里面去,那么此处如果不是第一次进入的话,那么缓存里面已经有了不用再次去获取.
* 此处做的工作就是从缓存中去获取已经找到过并存进来的构造方法和构造参数值列表.
* 还有注意,只有当我们参数中explicitArgs为空的时候,构造器才会被缓存
* */
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果缓存中存在则赋值.
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
/**
* 这里判断constructorToUse是否为空是因为上面有可能从缓存里面已经拿到了,如果拿到了则不需要进if里面去寻找,直接去调用创建实例化操作了.
* 这里重要的是if里面的代码.
* */
if (constructorToUse == null) {
// Need to resolve the constructor.
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
/**
* 构造器使用的参数
* */
ConstructorArgumentValues resolvedValues = null;
/**
* 最小参数个数,此值需要用来在循环寻找构造器时使用.
* 如果当当前循环到的构造器参数值个数小于这个最小值的话,那么说明就是不合适的,没必要继续下去.
* */
int minNrOfArgs;
/**
* 如果我们getBean的地方传入构造参数值列表,那么则最小参数个数就是我们传入的列表长度
* */
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
/**
* 如果我们没有传入构造器参数值列表,那么则去解析看有没有配置构造器参数列表,例如如下配置:
* <bean class="com.dh.aop.package1.Demo2" id="demo2">
* <constructor-arg index="0" value="111"></constructor-arg>
* <constructor-arg index="1" value="222"></constructor-arg>
* </bean>
* 这个时候,minNrOfArgs的值就是2
* 如果我们没有配置构造器参数的话,这个minNrOfArgs的值就是0
* */
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// Take specified constructors, if any.
/**
* 将该方法的参数构造器列表赋值给candidates
* */
Constructor<?>[] candidates = chosenCtors;
/**
* 如果传入的构造器列表为空,则通过class对象去拿
* 如果bd中设置了允许访问非public的构造器,那么则获取所有的构造器,否则获取public的构造器.
* 注意这里isNonPublicAccessAllowed的默认值为true.
* 如果获取构造器的时候出错当然就要抛异常.
* */
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
/**
* 对构造器进行排序:
* public的大于其他的权限
* 如果都是public的,那么参数越多越靠前.
* 可以看这个sort方法里面可以看到的
* */
AutowireUtils.sortConstructors(candidates);
/**
* 差异变量
* */
int minTypeDiffWeight = Integer.MAX_VALUE;
/**
* 有歧义的构造器,就是参数数量一致的,这种情况下的构造器就被列为有歧义的.
* 正常情况下,如果出现有歧义的构造器,那么就使用第一个,这取决于spring设置的宽松模式.
* 默认为宽松,如此的话就默认使用第一个构造器使用
* 如果设置为严格,则会报错
* 设置宽松/严格模式标志:beanDefinition.setLenientConstructorResolution
* */
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
/**
* 下面就是循环的拿构造器去校验判断选取一个合适的构造器了.在此之前我们总结一下上述代码做的事情.
* 1、定义constructorToUse、argsHolderToUse、argsToUse,这些分别用来存后面实际上需要使用的构造器、构造器参数、值等
* 2、如果getBean调用的时候传入了构造器参数,那么argsToUse的值就被赋值为传入的构造器参数,否则就尝试从缓存里面去拿constructorToUse和argsToUse
* 这个缓存就是当bean不是原型的时候实例化时找到的合适的构造器等参数,当然如果是第一次进来,或者bean是单例的,那么此缓存中肯定没有这个bean相关的构造器数据
* 3、如果缓存里面有,则直接实例化bean后放到wrapper中并return,如果不存在则需要再次进行一些操作
* 4、在不存在时,首先定义resolvedValues,这个是后续循环里面需要使用到的构造器使用的参数列表,定义minNrOfArgs,这个是最小参数个数,首先如果getBean传入了构造器参数
* 那么此值就是传入构造参数的长度,否则就尝试看我们有没有配置使用某个构造器,如果都没有,那么这个值就是0了,这个变量用来后面在循环构造器的时候筛选用的
* 5、然后定义candidates变量,然后将chosenCtors(是前面传入的构造器列表)赋值过去,如果它为空,那么则需要去通过class去拿构造器,拿的时候判断了一手
* 去拿BeanDefinition中的isNonPublicAccessAllowed,这个isNonPublicAccessAllowed意思为是否允许访问非public的构造器,如果为true,则去获取所有的构造器,否则只获取public的
* 6、然后对所有的构造器进行排序,规则为public>其他权限,参数个数多的>参数个数少的,至于为什么排序这个可能是spring认为参数越多的越科学吧
* 7、差异变量,这个看循环里面的代码才能理解
* 8、定义ambiguousConstructors为有歧义的构造器,意思就是如果两个构造器参数一致,那Spring就不知道该去用哪个,这时这两个构造器就被放入ambiguousConstructors集合中,他们两个就是有歧义的构造器
* ================================================================================
* 下面循环里面需要搞清楚的就是它具体是如何选取到合适的构造器来使用
* */
for (Constructor<?> candidate : candidates) {
/**
* 拿到当前构造方法的参数class数组
* */
Class<?>[] paramTypes = candidate.getParameterTypes();
/**
* 前面说了[constructorToUse]这个变量是当前确定使用的构造器,如果它不为空,那么说明我们已经确定了使用哪个构造器,那么就没必要继续下去了.
* 但[argsToUse.length > paramTypes.length]这个就比较难理解.
* 注意每次循环以后argsToUse的值就会改变为那次循环的构造器的参数,如果当前拿到的argsToUse参数列表的长度大于当前这个构造器的长度,那么说明上一次拿到的这个argsToUse比当前的这个更合适(上面也说过,Spring认为参数越多的越科学)
* 这里可以注意一下前面sort排序的时候,构造参数个数越多的越靠前,所以这里敢于用长度判断后直接break,因为如果上一次循环的构造器参数列表为2个,那么这一次(也就是下一次)的构造参数列表肯定不会比2大,那么说明对于参数个数而言,上一次的参数个数肯定不会比这一次少,那么肯定就更合适了呗
*/
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
/**
* 如果当前构造器的参数数量比最小参数列表数量小的时候,那么跳过这个构造器.
* minNrOfArgs的值有两个地方赋值了:
* 1、如果我们getBean时传入了其他参数,那么其他参数的个数就是minNrOfArgs的值
* 2、如果我们getBean没有传参数,那么minNrOfArgs的值就是我们配置让Spring指定使用某些参数的构造器,那么我们配置的参数列表数量也就是当前的minNrOfArgs
* 3、如果上述的情况都不存在,那么minNrOfArgs就是0了,大多数时候都是这种情况,如果都没配置,那么就得Spring自己慢慢而不存在此处的筛选了.
* 所以总结来说此处就是做了一个根据我们自己定义的来筛选的操作
* */
if (paramTypes.length < minNrOfArgs) {
continue;
}
/**
* 存储构造器需要的参数
* */
ArgumentsHolder argsHolder;
/**
* 此处resolvedValues不为空则说明getBean时传入的参数explicitArgs为空的,
* 因为上面的代码是如果explicitArgs不为空则不对resolvedValues赋值,否则就对resolvedValues赋值
* 此处先看else的代码,会更清晰.
* 如果传入的参数为空,那么则会去拿参数了
* */
if (resolvedValues != null) {
try {
/**
* 去拿到参数列表的名称,这里ConstructorPropertiesChecker.evaluate是这样做的:
* 如果构造方法上加入了ConstructorProperties注解,那么说明我们参数名称数组,如果没有这个注解,那么次数paramNames为空的
* */
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
/** 这里为空则代表我们没有通过注解去自定义参数名称,则通过ParameterNameDiscoverer去解析拿到构造器的参数名称列表 */
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
/** 解析拿到参数名称列表 */
paramNames = pnd.getParameterNames(candidate);
}
}
/**
* 此处会去获取这些参数名称的参数值,如果是自动注入的就会通过getBean获取,当前这种构造器注入的情况如果循环依赖则会报错的.
* 这里我们只需要知道,此处将构造器需要的参数值拿出来后并封装到了argsHolder中去.
* 当然如果你构造器里面给个Integer的参数,那肯定是会报错的,因为这里面会去Spring容器中拿这个Integer,结果呢,肯定是NoSuchBeanDefinitionException了
* 其余这里不用太过于细究,有兴趣可以详细看.
* */
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
else {
/**
* 到了这个else里面来,说明getBean调用的时候传入了构造器参数,那么就说明我们希望按照指定的构造器去初始化Bean.
* 那么这里就需要判断当前构造器的参数个数是否和我们希望的个数一样,如果不是,那么就循环去找下一个构造器,
* 如果和我们希望的是一样的,那么就将我们给的参数封装到argsHolder里面去
* */
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
/**
* 当到达这里的时候,至此我们拿到了:
* 1、构造器
* 2、构造器需要的参数和值
* 那么这里就去结算前面定义的那个差异值.
* 注意这里的:isLenientConstructorResolution意思是是否为宽松的模式,为true的时候是宽松,false的时候是严格,默认为true,这个东西前面已经说了.
* 这个差异值越小越那就说明越合适.
* 具体差异值如何计算出来的这个可以自行去看里面的代码,argsHolder.getTypeDifferenceWeight(paramTypes)
* */
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
/**
* 如果本次计算到的差异值比上一次获取到的差异值小,那么就需要做这几件事:
* 1、设置constructorToUse为当前的这个构造器
* 2、设置参数和参数值
* 3、给差异值赋值为当前计算出来的差异值
* 4、清空有歧义的集合(因为此时我们已经得到了更合适的构造器,所以有歧义的构造器里面保存的构造器已经没有存在的意义了)
* */
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
/**
* 如果已经找到过一次构造器,并且当前的差异值和上一次的差异值一致的话,那么说明这两个构造器是有歧义的,
* 那么就将这两个构造器放到[有歧义的构造器]集合中去.
* */
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
/**
* 到达这里的时候,如果还没有找到合适的构造器,那么则直接抛出异常,这个类没法实例化
* */
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
/**
* 如果存在歧义的构造器集合不为空,并且当前BeanDefinition为严格模式,那么则抛出异常,只有当BeanDefinition为宽松模式时,这种情况才不会抛异常
* */
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
/**
* 如果当前getBean没有传参数,那么则将当前的构造器和参数放到缓存里面去,可能Spring认为传入参数的情况下说不准我们准备怎么做,所以干脆我们自己传入参数的就不缓存了
* */
if (explicitArgs == null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
/**
* 以下没什么好说的,new示例出来,存入beanWrapper中,return回去
* */
try {
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;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via constructor failed", ex);
}
}
Annotation source: https://blog.51cto.com/u_14240433/4884874
The method is very long, we can summarize it as:
Determination of constructor parameters .
根据传入的explicitArgs参数判断
. If explicitArgs is not empty, the parameters can be determined directly, because explicitArgs is specified by the user when calling the bean, and there is such a method in the BeanFactory class:Object getBean(String name,Object... args)
. So if it's not empty, it can be directly determined that the constructor parameter is it. In addition, if the constructor parameters have been recorded in the cache, they can be used directly. It should be noted that the final type of the parameter may be the initial type or the initial type obtained in the cache. For example, if the parameter is required to be int, and the original parameter may be String, then even if the parameter is obtained in the cache, type conversion is required. filter to ensure that the parameter types exactly correspond to the corresponding constructor parameters.If neither of the above two situations can be determined. Then only further analysis. Obtain the configuration constructor information through mbd.getConstructorArgumentValues(). With the information in the configuration, you can obtain the corresponding parameter value information. The parameter value information includes the specified value, or it may be a reference to another bean. This processing delegate The resolveConstructorArguments method is given and returns the number of arguments that can be resolved.
Constructor determination . After we determine the parameters of the constructor, we can lock the corresponding constructor according to the parameters. The method of matching is to match according to the number of parameters. Before matching, the constructor needs to be sorted in descending order according to the number of public priority parameters, and the number of non-public constructor parameters in descending order.
Since the parameter value can also be set by specifying the parameter name, such as
<constructor-arg name="aa">
, then in this case, the parameter name in the constructor must be determined first. There are two ways, one is obtained by annotation, The other is obtained through the tool class ParameterNameDiscoverer in Spring.- Convert the corresponding parameter type according to the determined constructor . Mainly use the type converter provided in Spring or the custom type converter provided by the user for conversion.
- Verification of constructor uncertainty . Because sometimes even if the constructor, parameter names, parameter types, and parameter values are all determined, it is not necessary to directly lock the constructor. The parameters of different constructors are in a parent-child relationship, so here is a final verification.
- Instantiate the bean based on the instantiation strategy and the resulting constructor and constructor parameters
Parse instanitateBean
method
Now that we understand methods with parameters, let's take a look at the instantiation process of the default constructor without parameters.
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);
}
}
In fact, it is to obtain the instantiation strategy, and then instantiate the instantiate. Use ---9736d23580dbdd2cc04865977bb61166--- of parent class SimpleInstantiationStrategy
instantiate
.
- instantiation strategy
We mentioned the instantiation strategy multiple times, so what exactly is this? In fact, after the previous analysis, we have obtained all the information of instantiation. In fact, we can directly use reflection to instantiate objects, but Spring does not do this.
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
//如果有需要覆盖或者动态替换的方法需要使用cglib进行动态代理,如果没有的话则直接使用反射的方式进行实例化
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();
}
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);
}
}
CglibSubclassingInstantiationStrategy
public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
}
else {
try {
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
instance = enhancedSubclassConstructor.newInstance(args);
}
catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// SPR-10785: set callbacks directly on the instance instead of in the
// enhanced class (via the Enhancer) in order to avoid memory leaks.
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}
First of all, it is judged that if beanDefinition.getMethodOverrides() is empty, it means that the user uses the configuration method of replace or lookup, then the reflection method is used directly. When these two features are used, only dynamic proxies can be used.
Document the ObjectFactory that created the bean
Next, we continue to look at the doCreateBean method, where circular dependency checks are performed, etc.
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//是否需要提前曝光,单例&&允许循环依赖&&当前bean正在创建中,检测循环依赖
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");
}
// 为避免后期循环依赖,可以在 bean 初始化完成前将创建实例的 objectFactory加入缓存
// 对bean 再一次依赖引用,主要应用SmartInstantiationAwareBeanPostProcessor
// 其中我们熟悉的AOP就是在这里将advice 动态织入,若没有直接返回bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
-
earlySingletonExposure
: Example of early exposure -
mbd.isSingleton()
: Whether it is a singleton -
this.allowCircularReferences
: Whether to allow circular dependencies -
isSingletonCurrentlyInCreation(beanName)
: Whether the bean is being created
Here is an example where TestA depends on TestB, and TestB depends on TestA.
We have covered it in detail in our previous article. I won't go into details here.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。