序言
前面几篇文章介绍了Spring中几种方式下Bean对象的实例化的过程,那如果之前的几种都不满足,按照Spring中正常Bean的实例化步骤,该如何创建这个Bean对象呢?
测试类
我们先创建几个debug中用到的栗子。
Person
以一个平平无奇的Person对象的创建为切入点。
public class Person {
// 省略了get set和构造方法,但是debug过程中构造方法很重要。
private String name;
private int age;
}
person.xml
xml中bean标签配置了person对象信息,并且设置了scope = prototype
以及<constructor-arg>
。注释掉的<property>
标签其实加载逻辑和<constructor-arg>
是一样的,我们这里拿<constructor-arg>
为例。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="org.springframework.factoryMethod.Person" scope="prototype">
<bean id="person" class="org.springframework.factoryMethod.Person" scope="prototype">
<!-- <property name="age" value="22"/>-->
<!-- <property name="name" value="李四"/>-->
<constructor-arg name="age" value="18"/>
<constructor-arg name="name" value="张三"/>
</bean>
</bean>
</beans>
main
public class ConstructorTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("person.xml");
Person p1 = (Person)ac.getBean("person");
Person p2 = (Person)ac.getBean("person");
}
}
所以根据我们在xml中的配置,在Person
(p1)对象实例化中的流程大体如下:
- 获取构造器方法列表(因为类中可能定义很多的构造器方法)
- 遍历构造器,获取当前构造器方法的参数名称(name,age)
- 获取xml中配置的我们配置的具体属性值(18,张三)
- 将获取到的参数名称、值与构造器方法做匹配
- 计算构造器权重,确认最终使用的构造器
- 缓存当前所使用的的构造器方法,实例化Bean对象。
而当我们p2对象进行实例化时,就可以直接从缓存中进行获取。无需再重新遍历。
主流程方法
接下来我们回到doCreateBean
的主流程方法中的createBeanInstance
方法中,接着往下看。
doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
//这个beanWrapper是用来持有创建出来的bean对象的
BeanWrapper instanceWrapper = null;
//如果是单例对象,从factoryBeanInstanceCache缓存中移除该信息
if (mbd.isSingleton()) {
// 如果是单例对象,从factoryBean实例缓存中移除当前bean定义信息
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// 没有就创建实例
if (instanceWrapper == null) {
// 根据执行bean使用对应的策略创建新的实例,如,工厂方法,构造函数主动注入、简单初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//省略部分代码
return exposedObject;
}
createBeanInstance
debug时省略了之前提到的Supplier
和FactoryMethod
创建方法的步骤,我们直接从boolean resolved = false;
开始看。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 锁定class,根据设置的class属性或者根据className来解析class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 如果beanClass != null
// 并且,访问修饰符不是public修饰, 抛异常
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException;
}
// 获取Supplier
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
// 如果不为null,
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果工厂方法不为null,则采用工厂方法来实例化
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
//标记下,防止重复创建一个Bean
boolean resolved = false;
//是否需要自动装配
boolean autowireNecessary = false;
//如果args为null,则进行同步锁,获取构造方法
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?
//从SmartInstantiationAwareBeanPostProcessor中确认我们的构造器
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?
//获取首选的构造器,方法return null 自己自定义扩展
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// 如果没有特殊处理,则采用无参构造器来实例化对象
return instantiateBean(beanName, mbd);
}
此时来到了p1对象的创建,设置resolved等标志位后,因为此时缓存中resolvedConstructorOrFactoryMethod == null
,所以并不会进到下面的判断。
此时resolvedConstructorOrFactoryMethod == null
,并不会修改resolved的值,等到下面的 if 判断,因为在xml中设置了构造器参数,所以此时mbd.hasConstructorArgumentValues()
返回true,能够进到判断中,接下来我们看autowireConstructor
方法。
而我们的atowireMode共有5种,我们这里没有配置,所以no。
autowireConstructor
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
创建Bean实例的整体流程。
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
//创建BeanWrapperImpl对象
BeanWrapperImpl bw = new BeanWrapperImpl();
//初始化bw (设置ConversionService和工厂中所有的PropertyEditor) 用来属性转换
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
//如果有传入的参数,则直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
//声明一个要解析的args数组,默认为null
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
//将beanDefinition中解析完的构造函数和参数
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
//BeanDefinition中存在解析过的构造函数和参数 && 存在构造函数参数
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, true);
}
}
//如果缓存中没有解析好的构造器函数 || 参数构造器参数为空
if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.
// 如果传入的chosenCtors不为null,则使用chosenCtors,否则通过反射获取类中定义的构造器函数
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException;
}
}
//如果只有1个候选的构造器函数 && 传入参数explicitArgs = null && mbd中也没有构造器函数参数值
if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
//获取当前构造器函数
Constructor<?> uniqueCandidate = candidates[0];
//如果唯一的构造器函数的参数个数为0,则直接使用
if (uniqueCandidate.getParameterCount() == 0) {
synchronized (mbd.constructorArgumentLock) {
//mbd中缓存解析好的构造器函数或工厂方法
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
//mbd中标记构造器参数已解析
mbd.constructorArgumentsResolved = true;
//mbd中缓存解析好的构造器参数为EMPTY_ARGS
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
//通过反射进行bean的实例化并返回
bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// Need to resolve the constructor.
// 1.如果传入的chosenCtors参数不为null
// 2.autowireMode 选择的是构造器注入的方式(AUTOWIRE_CONSTRUCTOR)
// 有以上两种情况之一:说明需要自动装配,设置autowiring为true
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
//构造器的最小参数个数
int minNrOfArgs;
//如果传入的explicitArgs不为null,则minNrOfArgs = explicitArgs.length
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
//获取配置文件中配置的构造器参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
//创建ConstructorArgumentValues对象,
resolvedValues = new ConstructorArgumentValues();
//解析参数个数
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
//将符合条件的构造器方法进行排序
AutowireUtils.sortConstructors(candidates);
// 定义一个差异变量,变量的大小决定着构造函数是否能够被使用
int minTypeDiffWeight = Integer.MAX_VALUE;
// 不明确的构造函数集合,正常情况下差异值不可能相同
Set<Constructor<?>> ambiguousConstructors = null;
//定义一个用于UnsatisfiedDependencyException的列表
LinkedList<UnsatisfiedDependencyException> causes = null;
//遍历获取到的构造方法
for (Constructor<?> candidate : candidates) {
//获取每个构造方法的参数个数
int parameterCount = candidate.getParameterCount();
// 1. 已经找到选用的构造函数
// 2. 需要的参数个数小于当前的构造函数参数个数则终止,前面已经经过了排序操作
if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
// 当前构造器函数所需参数数量 < 要求的参数数量,跳过,遍历下一个
if (parameterCount < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
//获取构造器所需参数类型数组
Class<?>[] paramTypes = candidate.getParameterTypes();
if (resolvedValues != null) {
try {
// 获取构造函数上的ConstructorProperties注解中的参数
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
//如果没有上面注解,则获取构造器方法参数列表中的属性名称
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
//获取指定的构造器参数名称
paramNames = pnd.getParameterNames(candidate);
}
}
// 根据名称和数据类型创建argsHolder对象
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
//不存在构造函数参数列表需要解析的参数
else {
// Explicit arguments given -> arguments length must match exactly.
// 如果参数列表的数量与传入进来的参数数量不相等,继续遍历,否则构造参数列表封装对象
if (parameterCount != explicitArgs.length) {
continue;
}
// 构造函数没有参数的情况
argsHolder = new ArgumentsHolder(explicitArgs);
}
// 计算差异量,根据要参与构造函数的参数列表和本构造函数的参数列表进行计算
// 省略这部分代码
// 存在两种情况
// 1. 没有确定使用的构造器函数
// 2、存在模糊的构造函数并且不允许存在模糊的构造函数
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException;
}
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException;
}
/**
* 没有传入参与构造函数参数列表的参数时,对构造函数缓存到BeanDefinition中
* 1、缓存BeanDefinition进行实例化时使用的构造函数
* 2、缓存BeanDefinition代表的Bean的构造函数已解析完标识
* 3、缓存参与构造函数参数列表值的参数列表
*/
if (explicitArgs == null && argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
debug
具体流程
方法开始会创建BeanWrapper对象并初始化,初始化时会设置conversionService和注册BeanFactory中所有的Editors,目的是将值进行转换,因为我们在xml中配置的具体value都是字符串,比如说 age,而我们在具体类中对应的是Integer,在这里初始化后等到赋值时可以直接用。
protected void initBeanWrapper(BeanWrapper bw) {
bw.setConversionService(getConversionService());
registerCustomEditors(bw);
}
声明构造器变量以及参数变量,因为我们此时对象还没有加载,所以缓存中constructorArgumentsResolved
、argsToResolve
等变量目前都为null,所以这些判断都进不去。
缓存中没有,所以我们需要获取当前实例中的所有构造器,并挑选一个符合条件的作为我们Bean的实例的容器。当前Person对象中我定义了一个无参构造器和一个包含name和age的构造器方法,所以这里candidates长度为2.
如果只获取到了一个构造器方法 && 没有构造器函数的参数值(mbd.hasConstructorArgumentValues()
) && 也没有传入显示指定的参数(explicitArgs == null
)
则直接使用instantiate进行Bean的实例化,并设置缓存resolvedConstructorOrFactoryMethod
、constructorArgumentsResolved
、resolvedConstructorArguments
。
我们这里有两个构造器参数,所以进不来。
看是否需要进行自动装配
chosenCtors是方法的传参,这里是null,并且我们也没有在xml中配置 autowiring 属性,所以这里也进不来。
上面所有的条件都不满足,接下来就要根据我们获得的构造器方法列表和xml中配置的定义属性来挑选一个符合条件的构造器,作为对象实例化加载的容器。
获取到xml中配置的构造器参数。
解析参数个数,赋值给resolevedValues变量中。并将获取到的构造器进行排序操作。
排序:排序操作很重要,因为如果类中属性特别多,那么对应的生成的构造函数也可能会特别多,排序后再遍历会将不符合条件的直接continue,效率会大大提升。
遍历我们获取到的构造方法,因为做了排序,所以此时来到的是 name,age的构造方法。
如果已经在缓存中找到了构造函数 && 当前构造函数的参数个数(parameterCount) < 具体实例化时要用到的参数个数(argsToUse)。
说明没有再继续遍历的必要了,直接break。
如果当前构造方法的参数个数(parameterCount) < 我们需要实例化最小的参数个数 (minNrOfArgs),跳过这次循环 continue(当我们第二次循环condidates集合时,来到了无参构造,就会直接continue)
获取构造方法中的参数名称。
根据我们解析到xml中的值和当前构造方法的paramNames,创建并封装成argsHolder对象。
Spring中会计算每个构造器的权重,并通过逻辑选出最适合当前的构造器参数。
此时,将最终确认的构造器以及参数进行缓存。并调用instantiate方法进行bean的实例化创建并返回。
public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
mbd.constructorArgumentsResolved = true;
if (this.resolveNecessary) {
mbd.preparedConstructorArguments = this.preparedArguments;
}
else {
mbd.resolvedConstructorArguments = this.arguments;
}
}
}
此时!我们的p1对象已经创建完成,当我们p2对象再次进行创建时。
缓存中不为null,设置我们的resolved 和 autowireNecessary变量为true。
再次调用autowireConstructor
方法时。缓存不为null直接从缓存中找。找到后直接调用instantiate方法进行bean的实例化。(只有xml中配置 scope=“prototype” 才可以看到效果,不然创建完p1后直接放入 singletonObjects 缓存, 等到p2创建直接从singletonObjects中获取了)