实例化 Bean

在doCreateBean()代码 <2> 处,有一行代码instanceWrapper = createBeanInstance(beanName, mbd, args); 我们追踪进去看一下:

//AbstractAutowireCapableBeanFactory.java//创建Bean的实例对象protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.//解析beanName 为 classClass<?> beanClass = resolveBeanClass(mbd, beanName);//检查确认Bean是可实例化的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 回调,则使用给定的回调方法初始化策略Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}//使用 FactoryBean 的 factory-method 来创建,支持静态工厂和实例工厂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) {//构造函数自动注入进行实例化//一个类有多个构造函数,每个构造函数都有不同的参数,所以需要根据参数锁定构造函数进行 bean 的实例化return autowireConstructor(beanName, mbd, null, null);}else {//使用默认的无参构造方法实例化return instantiateBean(beanName, mbd);}}// Need to determine the constructor...//需要根据参数解析构造函数Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {//使用容器的自动装配特性,调用匹配的构造方法实例化return autowireConstructor(beanName, mbd, ctors, args);}// No special handling: simply use no-arg constructor.//使用默认的无参构造方法实例化return instantiateBean(beanName, mbd);}

这段代码中,Spring把Bean的实例话分为了4种方式

1.Supplier 回调
2.工厂方法初始化
3.构造函数自动注入初始化
4.默认无参构造方法初始化

一、Supplier 回调

如果存在 Supplier 回调,则调用 obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) 方法,进行初始化。Supplier是一个接口,定义如下:

public interface Supplier<T> {T get();
}

这个接口有什么作用?用于指定创建 bean 的回调。如果我们设置了这样的回调,那么其他的构造器或者工厂方法都会没有用
设置的地方在BeanDefinition的构造函数中,如:

// RootBeanDefinition.java
public <T> RootBeanDefinition(@Nullable Class<T> beanClass, String scope, @Nullable Supplier<T> instanceSupplier) {super();setBeanClass(beanClass);setScope(scope);// 设置 instanceSupplier 属性setInstanceSupplier(instanceSupplier);
}

二、工厂方法初始化

如果存在工厂方法,则使用工厂方法进行初始化。这部分代码非常长,很复杂,这里就不详细说了。

三、构造函数自动注入初始化

首先判断缓存,如果缓存中存在(resolved==true),即已经解析过了,则直接使用已经解析了的。否则,先解析构造函数,然后通过构造函数自动注入初始化。

  • 3.1、autowireConstructor()

autowireConstructor() 这个初始化方法,我们可以简单理解为通过带有参数的构造方法,来初始化 Bean 对象。带有参数的实例化过程相当复杂,因为存在这不确定性,所以在判断对应参数上做了大量工作。
代码段如下:

//AbstractAutowireCapableBeanFactory.javapublic BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,@Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) {// 封装 BeanWrapperImpl 对象,并完成初始化BeanWrapperImpl bw = new BeanWrapperImpl();this.beanFactory.initBeanWrapper(bw);Constructor<?> constructorToUse = null;// 最终使用的构造函数ArgumentsHolder argsHolderToUse = null;// 构造参数Object[] argsToUse = null;// 构造参数// 判断有无显式指定参数,如果有则优先使用,如 xxxBeanFactory.getBean("teacher", "李华",3);
<1>   if (explicitArgs != null) {argsToUse = explicitArgs;}// 没有显式指定参数,则解析配置文件中的参数
<2>   else {Object[] argsToResolve = null;synchronized (mbd.constructorArgumentLock) {// 优先尝试从缓存中获取,spring对参数的解析过程是比较复杂也耗时的,所以这里先尝试从缓存中获取已经解析过的构造函数参数constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;//如果构造方法和参数都不为Nullif (constructorToUse != null && mbd.constructorArgumentsResolved) {// Found a cached constructor...// 获取缓存中的构造参数argsToUse = mbd.resolvedConstructorArguments;if (argsToUse == null) {argsToResolve = mbd.preparedConstructorArguments;}}}// 缓存中存在,则解析存储在 BeanDefinition 中的参数// 如给定方法的构造函数 A(int ,int ),则通过此方法后就会把配置文件中的("1","1")转换为 (1,1)// 缓存中的值可能是原始值也有可能是最终值if (argsToResolve != null) {argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);}}// 缓存不存在,则需要解析构造函数参数,以确定使用哪一个构造函数来进行实例化
<3>   if (constructorToUse == null) {// Need to resolve the constructor.boolean autowiring = (chosenCtors != null ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);// 用于承载解析后的构造函数参数的值ConstructorArgumentValues resolvedValues = null;//参数个数
<4>       int minNrOfArgs;if (explicitArgs != null) {minNrOfArgs = explicitArgs.length;}else {// 从 BeanDefinition 中获取构造参数,也就是从配置文件中提取构造参数ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();resolvedValues = new ConstructorArgumentValues();// 能解析到的参数个数minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);}// Take specified constructors, if any.//使用指定的构造函数,如果有的话
<5>       Constructor<?>[] candidates = chosenCtors;//没有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 且 参数最多的构造函数会排在第一位
<6>       AutowireUtils.sortConstructors(candidates);int minTypeDiffWeight = Integer.MAX_VALUE;//模棱两可的构造函数集合Set<Constructor<?>> ambiguousConstructors = null;LinkedList<UnsatisfiedDependencyException> causes = null;// 迭代所有构造函数,解析确定使用哪一个构造函数
<7>       for (Constructor<?> candidate : candidates) {// 获取该构造函数的参数类型
<8>           Class<?>[] paramTypes = candidate.getParameterTypes();// 如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数参数个数,则终止。// 因为,已经按照参数个数降序排列了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;}// 参数个数不等,跳过if (paramTypes.length < minNrOfArgs) {continue;}// 参数持有者 ArgumentsHolder 对象ArgumentsHolder argsHolder;
<9>           if (resolvedValues != null) {try {// 获取注解上的参数名称 by @ConstructorPropertiesString[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);if (paramNames == null) {ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();if (pnd != null) {// 获取指定构造函数的参数名称paramNames = pnd.getParameterNames(candidate);}}// 根据构造函数和构造参数,创建参数持有者 ArgumentsHolder 对象argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,getUserDeclaredConstructor(candidate), autowiring);}catch (UnsatisfiedDependencyException ex) {if (this.beanFactory.logger.isTraceEnabled()) {this.beanFactory.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 {// Explicit arguments given -> arguments length must match exactly.if (paramTypes.length != explicitArgs.length) {continue;}// 根据 getBean()传入的 explicitArgs ,创建 ArgumentsHolder 对象argsHolder = new ArgumentsHolder(explicitArgs);}//通过构造函数参数差异值对比,得出最适合使用的构造函数// isLenientConstructorResolution 判断解析构造函数的时候是否以宽松模式还是严格模式(默认宽松)// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常// 宽松模式:使用具有"最接近的模式"进行匹配int typeDiffWeight = (mbd.isLenientConstructorResolution() ?argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));// Choose this constructor if it represents the closest match.// 如果它代表着当前最接近的匹配则选择其作为构造函数//差异值越小,越匹配,每次和分数最小的去比较
<10>          if (typeDiffWeight < minTypeDiffWeight) {constructorToUse = candidate;argsHolderToUse = argsHolder;argsToUse = argsHolder.arguments;minTypeDiffWeight = typeDiffWeight;ambiguousConstructors = null;}// 如果两个构造方法与参数值类型列表之间的差异量一致,那么这两个方法都可以作为// 候选项,这个时候就出现歧义了,这里先把有歧义的构造方法放入ambiguousConstructorselse 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)");}//如果模棱两可的构造函数不为空,且为 严格模式,则抛异常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);}// 将解析的构造函数、参数 加入缓存
<11>      if (explicitArgs == null) {/** 缓存相关信息,比如:*   1. 已解析出的构造方法对象 resolvedConstructorOrFactoryMethod*   2. 构造方法参数列表是否已解析标志 constructorArgumentsResolved*   3. 参数值列表 resolvedConstructorArguments 或 preparedConstructorArguments** 这些信息可用在其他地方,用于进行快捷判断*/argsHolderToUse.storeCache(mbd, constructorToUse);}}try {//获取Bean的初始化策略final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();Object beanInstance;//创建 Bean 对象
<12>      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 中bw.setBeanInstance(beanInstance);return bw;}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean instantiation via constructor failed", ex);}}

代码很长,但不要慌,我们来一步步分析:

<1>处,判断有无显式指定构造参数
<2>处,没有显式指定参数,则从缓存中获取
<3>处,缓存不存在,解析构造函数参数
<4>处,获取构造参数个数
<5>处,获取所有构造方法
<6>处,对所有构造方法排序
<7>处,遍历所有构造方法
<8>处,通过参数校验构造方法
<9>处,创建参数持有者 ArgumentsHolder
<10>处,筛选出符合的构造方法
<11>处,将解析的构造函数、参数 加入缓存
<12>处,实例化Bean对象
  • 3.1.1、判断有无显式指定构造参数

explicitArgs:外部传入的指定构造参数
argsToUse:要使用的构造参数
explicitArgs:是指外部传入的指定构造参数,例如xxxBeanFactory.getBean(“teacher”, “李华”,3),(李华和3)就是传入的指定参数。
argsToUse 是我们实例化时要使用的构造参数,这里判断如果explicitArgs不为null的化,就把explicitArgs赋值给 argsToUse。

  • 3.1.2、没有显式指定参数,则从缓存中获取
Object[] argsToResolve = null;synchronized (mbd.constructorArgumentLock) {// 优先尝试从缓存中获取,spring对参数的解析过程是比较复杂也耗时的,所以这里先尝试从缓存中获取已经解析过的构造函数参数constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;//如果构造方法和参数都不为Nullif (constructorToUse != null && mbd.constructorArgumentsResolved) {// Found a cached constructor...// 获取缓存中的构造参数argsToUse = mbd.resolvedConstructorArguments;if (argsToUse == null) {argsToResolve = mbd.preparedConstructorArguments;}}}// 缓存中存在,则解析存储在 BeanDefinition 中的参数// 如给定方法的构造函数 A(int ,int ),则通过此方法后就会把配置文件中的("1","1")转换为 (1,1)// 缓存中的值可能是原始值也有可能是最终值if (argsToResolve != null) {argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);}

首先从缓存中mbd.resolvedConstructorOrFactoryMethod获取构造方法,如果缓存中存在构造方法和参数,就解析构造参数。
因为缓存中的构造参数不一定是最终值,如给定方法的构造函数 A(int ,int ),则通过此方法后就会把配置文件中的(“1”,“1”)转换为 (1,1)

  • 3.1.3、缓存不存在,解析构造函数参数

如果缓存不存在,则需要解析构造函数参数,以确定使用哪一个构造函数来进行实例化

  • 3.1.4、获取构造参数个数
 //参数个数
int minNrOfArgs;
if (explicitArgs != null) {minNrOfArgs = explicitArgs.length;
}
else {// 从 BeanDefinition 中获取构造参数,也就是从配置文件中提取构造参数ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();resolvedValues = new ConstructorArgumentValues();// 能解析到的参数个数minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}

如果explicitArgs不为null,则直接获取。
为null:需要解析保存在 BeanDefinition 构造函数中指定的参数并获取能解析到的参数个数

  • 3.1.5、获取所有构造方法

先尝试获取指定的构造方法,如果没有,则利用反射获取所有构造方法

  • 3.1.6、对所有构造方法排序

排序的主要目的,是为了能够更加方便的找到最匹配的构造方法,因为构造方法的确认是根据参数个数确认的。排序的规则是:先按照 public / 非 public 构造方法升序,再按照构造参数数量降序。

  • 3.1.7、遍历所有构造方法

遍历所有构造方法,筛选出最匹配的一个

  • 3.1.8、通过参数校验构造方法
// 获取该构造函数的参数类型Class<?>[] paramTypes = candidate.getParameterTypes();///这里的判断构造方法和构造方法参数 都不是空,又由于之前对构造方法做了排序。所以在使用的参数的个数已经大于当前构造方法的参数个数的时候,实际上已经取到了想要的构造方法。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;}// 当前的构造参数个数小于我们要求的个数,跳过if (paramTypes.length < minNrOfArgs) {continue;}

这段代码也不复杂,第一个if是break分支,满足条件就跳出for循环,到这里就意为着找到了最匹配的构造方法。
EX: 假设现在有一组构造方法按照上面的排序规则进行排序,排序结果如下:

 1. public Hello(Object, Object, Object)2. public Hello(Object, Object)3. public Hello(Object)4. protected Hello(Integer, Object, Object, Object)5. protected Hello(Integer, Object, Object)6. protected Hello(Integer, Object)

由于是按降序排序的,所以会先去匹配构造方法1,发现 argsToUse.length > paramTypes.length

第二个if是快速判断当前构造方法是否符合我们的要求。

paramTypes:当前构造方法的参数个数
minNrOfArgs:我们要求的构造方法的参数个数 如果当前的构造参数个数小于我们要求的个数,说明当前构造方法不符合我们的要求,直接 continue

  • 3.1.9、创建参数持有者 ArgumentsHolder
  // 参数持有者 ArgumentsHolder 对象
ArgumentsHolder argsHolder;
if (resolvedValues != null) {try {// 获取注解上的参数名称 by @ConstructorPropertiesString[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);if (paramNames == null) {// ParameterNameDiscoverer 是用于解析方法和构造函数的参数名称的接口,为参数名称探测器ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();if (pnd != null) {// 获取指定构造函数的参数名称paramNames = pnd.getParameterNames(candidate);}}// 根据构造函数和构造参数,创建参数持有者 ArgumentsHolder 对象argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,getUserDeclaredConstructor(candidate), autowiring);}catch (UnsatisfiedDependencyException ex) {if (this.beanFactory.logger.isTraceEnabled()) {this.beanFactory.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 {// Explicit arguments given -> arguments length must match exactly.if (paramTypes.length != explicitArgs.length) {continue;}// 根据 getBean()传入的 explicitArgs ,创建 ArgumentsHolder 对象argsHolder = new ArgumentsHolder(explicitArgs);
}

这里主要有两个逻辑:

resolvedValues != null:即没有显示指定构造参数
resolvedValues == null:即显示指定了构造参数

  • 第一个分支:

先通过@ConstructorProperties注解获取构造参数名称,如果获取不到,再通过ParameterNameDiscoverer获取,最后创建 ArgumentsHolder

  • 第二个分支:

直接使用显示传入的构造参数 explicitArgs 来 new 一个ArgumentsHolder
将参数包装成 ArgumentsHolder 对象。该对象用于保存参数,我们称之为参数持有者。在这个过程中再次解析构造参数,进行类型转换,如把配置文件中的string转换成需要的int。
当将对象包装成 ArgumentsHolder 对象后,我们就可以通过它来进行构造函数匹配。匹配分为严格模式和宽松模式:

严格模式:解析构造函数时,必须所有参数都需要匹配,否则抛出异常。
宽松模式:从模棱两可的构造方法中,选择最接近的。 判断的依据是根据BeanDefinition 的 isLenientConstructorResolution 属性(该参数是我们在构造 AbstractBeanDefinition 对象是传递的)来获取类型差异权重(typeDiffWeight) 的。

  • 3.1.10、筛选出符合的构造方法
//通过构造函数参数差异值对比,得出最适合使用的构造函数// isLenientConstructorResolution 判断解析构造函数的时候是否以宽松模式还是严格模式(默认宽松)// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常// 宽松模式:使用具有"最接近的模式"进行匹配int typeDiffWeight = (mbd.isLenientConstructorResolution() ?argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));// Choose this constructor if it represents the closest match.// 如果它代表着当前最接近的匹配则选择其作为构造函数//差异值越小,越匹配,每次和分数最小的去比较if (typeDiffWeight < minTypeDiffWeight) {constructorToUse = candidate;argsHolderToUse = argsHolder;argsToUse = argsHolder.arguments;minTypeDiffWeight = typeDiffWeight;ambiguousConstructors = null;}// 如果两个构造方法与参数值类型列表之间的差异量一致,那么这两个方法都可以作为// 候选项,这个时候就出现歧义了,这里先把有歧义的构造方法放入ambiguousConstructorselse 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)");/如果模棱两可的构造函数不为空,且为 严格模式,则抛异常
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);}

先通过计算得出当前构造方法的差异值typeDiffWeight,每次和分数最小的去比较,筛选出差异值最小的,最终比较出一个最匹配的构造方法。
差异值大于最小差异值的,加入到候选集合ambiguousConstructors,我称之为模棱两可的构造方法,该集合在《宽松模式》下使用。

至此,所有构造方法都遍历完毕。如果仍没有筛选出构造方法,抛出异常。
如果模棱两可的构造方法不为空,但模式为 严格模式,则抛异常。

  • 3.1.11、将解析的构造函数、参数 加入缓存
// 将解析的构造函数、参数 加入缓存
if (explicitArgs == null) {/** 缓存相关信息,比如:*   1. 已解析出的构造方法对象 resolvedConstructorOrFactoryMethod*   2. 构造方法参数列表是否已解析标志 constructorArgumentsResolved*   3. 参数值列表 resolvedConstructorArguments 或 preparedConstructorArguments** 这些信息可用在其他地方,用于进行快捷判断*/argsHolderToUse.storeCache(mbd, constructorToUse);}

继续追踪:

 // ArgumentsHolder.javapublic final Object rawArguments[];public final Object arguments[];public final Object preparedArguments[];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;}}}

相信大家看到这里应该对resolvedConstructorOrFactoryMethodresolvedConstructorArguments等这几个参数很熟悉。
正如你所想,在前面判断缓存中是否存在的时候,就是通过这几个参数来判断的。

  • 3.1.12、实例化Bean对象
    strategy.instantiate 这部分代码还是挺多的,下回分析。
  • 1.3.2、图解流程
    因为这段代码还是挺复杂的,所以我画了一个(explicitArgs=null)的分支流程图,便于理解
  • 1.3、默认无参构造方法初始化
    经过有参构造方法初始化源码的摧残之后,再来看无参的源码,会发现简单多了。
return instantiateBean(beanName, mbd);

继续追踪:

//使用默认的无参构造方法实例化Bean对象protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {try {Object beanInstance;final BeanFactory parent = this;//获取系统的安全管理接口,JDK标准的安全管理APIif (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);}}

看过有参构造方法初始化的源码之后,再看看无参的,发现代码真的简单太多了,没有复杂的确定构造参数、构造方法的逻辑。

instantiate(mbd, beanName, parent)

//SimpleInstantiationStrategy.java//使用初始化策略实例化Bean对象@Overridepublic Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {// Don't override the class with CGLIB if no overrides.// 没有覆盖,直接使用反射实例化即可if (!bd.hasMethodOverrides()) {Constructor<?> constructorToUse;synchronized (bd.constructorArgumentLock) {//从缓存中获取对象的构造方法或工厂方法constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;//缓存没有if (constructorToUse == null) {//使用JDK的反射机制,判断要实例化的Bean是否是接口final Class<?> clazz = bd.getBeanClass();if (clazz.isInterface()) {throw new BeanInstantiationException(clazz, "Specified class is an interface");}try {if (System.getSecurityManager() != null) {//这里是一个匿名内置类,使用反射机制获取Bean的构造方法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);}}}//使用BeanUtils实例化,通过反射机制调用”构造方法.newInstance(arg)”来进行实例化return BeanUtils.instantiateClass(constructorToUse);}else {// Must generate CGLIB subclass.//有方法覆盖,使用CGLIB来实例化对象//方法覆盖,在调用目标方法的时候,对调用过程进行拦截,调用实现增强功能的拦截器,返回原来实例的代理//所以要用cglib动态代理return instantiateWithMethodInjection(bd, beanName, owner);}}

很简单的几个步骤:

1.判断有无方法覆盖
2.尝试从缓存中获取构造方法
3.校验bean是否为interface
4.利用反射获取默认构造方法
5.利用BeanUtils实例化

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);// 使用构造方法,创建对象 newInstancereturn (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));}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());}}

先设置强吻访问,然后newInstance()创建对象。

总结:对于 createBeanInstance() 方法而言,他就是选择合适实例化策略来为 bean 创建实例对象,具体的策略有:

 1.Supplier 回调方式2.工厂方法初始化3.构造函数自动注入初始化4.默认构造函数注入。

其中,工厂方法初始化和构造函数自动注入初始化两种方式最为复杂,主要是因为构造函数和构造参数的不确定性,Spring 需要花大量的精力来确定构造函数和构造参数,如果确定了则好办,直接选择实例化策略即可。

当然,在实例化的时候会根据是否有需要覆盖或者动态替换掉的方法,因为存在覆盖或者织入的话需要创建动态代理将方法织入,这个时候就只能选择 CGLIB 的方式来实例化,否则直接利用反射的方式即可,方便快捷。

最后:到这里实例化Bean的代码就分析完了。

文章转自:https://cloud.tencent.com/developer/article/1508894

Spring Ioc源码分析 之 Bean的加载(4):实例化Bean(createBeanInstance()方法)相关推荐

  1. Spring Ioc源码分析 之 Bean的加载(6):属性填充(populateBean())

    "属性填充",也是在populateBean()方法中. 首先回顾下CreateBean的主流程: 如果是单例模式,从factoryBeanInstanceCache 缓存中获取B ...

  2. Spring Ioc源码分析 之 Bean的加载(5):循环依赖处理(populateBean())

    首先回顾下Bean加载的主流程: 1.如果是单例模式,从factoryBeanInstanceCache 缓存中获取BeanWrapper 实例对象并删除缓存 2.调用 createBeanInsta ...

  3. Spring Ioc 源码分析(一)--Spring Ioc容器的加载

    1.目标:熟练使用spring,并分析其源码,了解其中的思想.这篇主要介绍spring ioc 容器的加载 2.前提条件:会使用debug 3.源码分析方法:Intellj idea debug 模式 ...

  4. 框架源码专题:springIOC的加载过程,bean的生命周期,结合spring源码分析

    文章目录 1.BeanFactory和ApplicationContext的区别? 2. IOC与 Bean的加载过程 ①:初始化容器DefaultListableBeanFactory ②:创建读取 ...

  5. java获取当前周一_Java互联网架构-Spring IOC源码分析

    欢迎关注头条号:java小马哥 周一至周日下午三点半!精品技术文章准时送上!!! 精品学习资料获取通道,参见文末 源码介绍之前,看几个问题: Bean的承载对象是什么? Bean的定义如何存储的? B ...

  6. Spring Ioc源码分析 之 Bean的加载(7):初始化

    接着分析doCreateBean()的第6步--初始化 bean 实例对象 首先回顾下CreateBean的主流程: 如果是单例模式,从factoryBeanInstanceCache 缓存中获取Be ...

  7. Spring Ioc 源码分析(一)- XML 解析

    2019独角兽企业重金招聘Python工程师标准>>> 注 :源码对应版本为 4.2.8.RELEASE 引入Spring依赖的时候,是否发现spring依赖有spring-bean ...

  8. Myabtis源码分析五-Mybatis配置加载完全图解,建造者模式的使用,涵盖Java各种技术栈

    private SqlSessionFactory sqlSessionFactory; @Before public void init() throws IOException { //----- ...

  9. nhibernate源码分析之六: Criteria数据加载

    ICriteria是使用Expression进行数据加载的接口, 提供了设置表达式(Expression), 排序方式(Order), 分页记录等操作. 它使用一种类似于SQL语句where表达表的方 ...

最新文章

  1. 动态代理:JDK动态代理和CGLIB代理的区别
  2. wxWidgets:键盘 wxWidgets 示例
  3. 【数字图像处理】一.MFC详解显示BMP格式图片
  4. vue的 v-for 循环中图片加载路径问题
  5. 关于python中带下划线的变量和函数 的意义,class类带一个下划线和带两个下划线的定义
  6. Hadoop日志分析工具——White Elephant
  7. Height Half Values
  8. 支付宝回应手机黑产;微软将允许员工永久在家办公;Flutter 1.22 正式发布|极客头条
  9. 如何用git将本地文件放到github上
  10. vs 生成get set_使用EasyCode+Lombok快速生成增删查改的代码
  11. python:查看某个数字类型的信息,比如最大有效值
  12. vb.net使用hook技术之键盘鼠标钩子
  13. 怎样解决Mac电脑键盘上的大写锁定键灯不亮?
  14. 大二狗卸任社团职位以及对专业发展方向的思考与总结
  15. MPB:南土所褚海燕组-土壤宏转录组学样本前处理与数据分析
  16. Xshell安装Docker并安装mysql5.7
  17. spring boot test 异常之 could not initialize proxy [*Money#31] - no Session
  18. 跨进程读取ListView(CListCtrl)内容
  19. vulnhub_GoldenEye: 1
  20. 按钮自动发光用html怎么弄,HTML+CSS+JS发光开关按钮

热门文章

  1. 设计模式--建造者模式--简记
  2. IE报vuex requires a Promise polyfill in this browser问题解决
  3. HTML中的div标签
  4. 转:C#判断ContextMenuStrip右键菜单的来源(从哪个控件弹出来的)
  5. Google 联合 Plaxo 对 OpenID 进行改进
  6. Go 语言 cannot find module providing package github.com/
  7. Python学习:深入Python流程控制
  8. Latex入门:编辑器(texmaker+texlive)安装
  9. 【Python】统计字符串里某个字符或子字符串出现的次数
  10. 【笔记】基于 Mask R-CNN 的玉米田间杂草检测方法