上篇文章Spring Ioc源码分析 之 Bean的加载(四):createBean()中咱们分析了
doCreateBean()
方法的大体流程,这篇文章咱们就详细分析下实例化 bean的createBeanInstance()
方法,剩下的步骤将在其余文章中介绍。java
简言:
实例化Bean的本质其实就是找到一个合适的构造方法,而后经过构造方法调用newInstance()
来实例化Bean。
这样看起来实例化Bean的过程很简单,但其实Spring花费了大量经历去寻找合适的构造方法。spring
在doCreateBean()
代码 <2> 处,有一行代码instanceWrapper = createBeanInstance(beanName, mbd, args);
这段代码就是实例化Bean的过程。
咱们追踪进去看一下:缓存
//AbstractAutowireCapableBeanFactory.java //建立Bean的实例对象 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // Make sure bean class is actually resolved at this point. //解析beanName 为 class Class<?> 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种方式:安全
若是存在 Supplier 回调,则调用 obtainFromSupplier(Supplier<?> instanceSupplier, String beanName)
方法,进行初始化。
Supplier是一个接口,定义以下:app
public interface Supplier<T> { T get(); }
这个接口有什么做用?用于指定建立 bean 的回调。若是咱们设置了这样的回调,那么其余的构造器或者工厂方法都会没有用
设置的地方在BeanDefinition的构造函数中,如:less
// RootBeanDefinition.java public <T> RootBeanDefinition(@Nullable Class<T> beanClass, String scope, @Nullable Supplier<T> instanceSupplier) { super(); setBeanClass(beanClass); setScope(scope); // 设置 instanceSupplier 属性 setInstanceSupplier(instanceSupplier); }
若是存在工厂方法,则使用工厂方法进行初始化。这部分代码很是长,很复杂,这里就不详细说了。ide
首先判断缓存,若是缓存中存在(resolved==true),即已经解析过了,则直接使用已经解析了的。不然,先解析构造函数,而后经过构造函数自动注入初始化。函数
autowireConstructor()
这个初始化方法,咱们能够简单理解为经过带有参数的构造方法,来初始化 Bean 对象。带有参数的实例化过程至关复杂,由于存在这不肯定性,因此在判断对应参数上作了大量工做。
代码段以下:源码分析
//AbstractAutowireCapableBeanFactory.java public 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; //若是构造方法和参数都不为Null if (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 @ConstructorProperties String[] 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; } // 若是两个构造方法与参数值类型列表之间的差别量一致,那么这两个方法均可以做为 // 候选项,这个时候就出现歧义了,这里先把有歧义的构造方法放入ambiguousConstructors 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)"); } //若是模棱两可的构造函数不为空,且为 严格模式,则抛异常 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); } }
代码很长,但不要慌,咱们来一步步分析:性能
外部传入的指定构造参数
要使用的构造参数
explicitArgs 是指外部传入的指定构造参数,例如xxxBeanFactory.getBean("teacher", "李华",3)
,(李华和3)就是传入的指定参数。
argsToUse 是咱们实例化时要使用的构造参数,这里判断若是explicitArgs不为null的化,就把explicitArgs赋值给 argsToUse。
Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { // 优先尝试从缓存中获取,spring对参数的解析过程是比较复杂也耗时的,因此这里先尝试从缓存中获取已经解析过的构造函数参数 constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod; //若是构造方法和参数都不为Null if (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)
若是缓存不存在,则须要解析构造函数参数,以肯定使用哪个构造函数来进行实例化
//参数个数 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 构造函数中指定的参数
并获取能解析到的参数个数
先尝试获取指定的构造方法,若是没有,则利用反射获取全部构造方法
排序的主要目的,是为了可以更加方便的找到最匹配的构造方法,由于构造方法的确认是根据参数个数确认的。排序的规则是:先按照 public / 非 public 构造方法升序,再按照构造参数数量降序。
遍历全部构造方法,筛选出最匹配的一个
// 获取该构造函数的参数类型 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是快速判断当前构造方法是否符合咱们的要求。
// 参数持有者 ArgumentsHolder 对象 ArgumentsHolder argsHolder; if (resolvedValues != null) { try { // 获取注解上的参数名称 by @ConstructorProperties String[] 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); }
这里主要有两个逻辑:
第一个分支:
先经过@ConstructorProperties
注解获取构造参数名称,若是获取不到,再经过ParameterNameDiscoverer
获取,最后建立 ArgumentsHolder
第二个分支:
直接使用显示传入的构造参数 explicitArgs 来 new 一个ArgumentsHolder
将参数包装成 ArgumentsHolder
对象。该对象用于保存参数,咱们称之为参数持有者。在这个过程当中再次解析构造参数,进行类型转换,如把配置文件中的string转换成须要的int。
当将对象包装成 ArgumentsHolder 对象后,咱们就能够经过它来进行构造函数匹配。匹配分为严格模式和宽松模式:
严格模式:解析构造函数时,必须全部参数都须要匹配,不然抛出异常。
宽松模式:从模棱两可的构造方法中,选择最接近的。
判断的依据是根据 BeanDefinition 的 isLenientConstructorResolution
属性(该参数是咱们在构造 AbstractBeanDefinition 对象是传递的)来获取类型差别权重(typeDiffWeight) 的。
//经过构造函数参数差别值对比,得出最适合使用的构造函数 // 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; } // 若是两个构造方法与参数值类型列表之间的差别量一致,那么这两个方法均可以做为 // 候选项,这个时候就出现歧义了,这里先把有歧义的构造方法放入ambiguousConstructors 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)"); /若是模棱两可的构造函数不为空,且为 严格模式,则抛异常 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
,我称之为模棱两可的构造方法,该集合在《宽松模式》下使用。
至此,全部构造方法都遍历完毕。若是仍没有筛选出构造方法,抛出异常。
若是模棱两可的构造方法不为空,但模式为 严格模式,则抛异常。
// 将解析的构造函数、参数 加入缓存 if (explicitArgs == null) { /* * 缓存相关信息,好比: * 1. 已解析出的构造方法对象 resolvedConstructorOrFactoryMethod * 2. 构造方法参数列表是否已解析标志 constructorArgumentsResolved * 3. 参数值列表 resolvedConstructorArguments 或 preparedConstructorArguments * * 这些信息可用在其余地方,用于进行快捷判断 */ argsHolderToUse.storeCache(mbd, constructorToUse); }
继续追踪:
// ArgumentsHolder.java public 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; } } }
相信你们看到这里应该对resolvedConstructorOrFactoryMethod
和 resolvedConstructorArguments
等这几个参数很熟悉。
正如你所想,在前面判断缓存中是否存在的时候,就是经过这几个参数来判断的。
strategy.instantiate
//SimpleInstantiationStrategy.java public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, final Constructor<?> ctor, @Nullable Object... args) { // 没有方法覆盖,直接使用反射实例化便可 if (!bd.hasMethodOverrides()) { if (System.getSecurityManager() != null) { // use own privileged to change accessibility (when security is on) // 设置构造方法,可访问 AccessController.doPrivileged((PrivilegedAction<Object>) () -> { ReflectionUtils.makeAccessible(ctor); return null; }); } // 经过 BeanUtils 直接使用构造函数实例化 Bean 对象 return (args != null ? BeanUtils.instantiateClass(ctor, args) : BeanUtils.instantiateClass(ctor)); } else { // 使用 CGLIB 建立代理对象 //方法覆盖,在调用目标方法的时候,对调用过程进行拦截,调用实现加强功能的拦截器,返回原来实例的代理 //因此要用cglib动态代理 return instantiateWithMethodInjection(bd, beanName, owner, ctor, args); } }
BeanUtils.instantiateClass(ctor, args)
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { Assert.notNull(ctor, "Constructor must not be null"); try { // 设置构造方法,可访问 ReflectionUtils.makeAccessible(ctor); // 使用构造方法,建立对象 newInstance return (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()); } }
由于这段代码仍是挺复杂的,因此我画了一个(explicitArgs=null)的分支流程图,便于理解。
通过有参构造方法初始化源码的摧残以后,再来看无参的源码,会发现简单多了。
return instantiateBean(beanName, mbd);
继续追踪:
//使用默认的无参构造方法实例化Bean对象 protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; //获取系统的安全管理接口,JDK标准的安全管理API 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); } }
看过有参构造方法初始化的源码以后,再看看无参的,发现代码真的简单太多了,没有复杂的肯定构造参数、构造方法的逻辑。
instantiate(mbd, beanName, parent)
//SimpleInstantiationStrategy.java //使用初始化策略实例化Bean对象 @Override public 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); } }
很简单的几个步骤:
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); // 使用构造方法,建立对象 newInstance return (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 建立实例对象,具体的策略有:
Supplier 回调方式
工厂方法初始化
构造函数自动注入初始化
默认构造函数注入。
其中,工厂方法初始化和构造函数自动注入初始化两种方式最为复杂,主要是由于构造函数和构造参数的不肯定性,Spring 须要花大量的精力来肯定构造函数和构造参数,若是肯定了则好办,直接选择实例化策略便可。
固然,在实例化的时候会根据是否有须要覆盖或者动态替换掉的方法,由于存在覆盖或者织入的话须要建立动态代理将方法织入,这个时候就只能选择 CGLIB 的方式来实例化,不然直接利用反射的方式便可,方便快捷。
最后:
到这里实例化Bean的代码就分析完了,这部分源码看起来仍是有难度的,看的我头发的慌了,写的也挺累的,但仍是会继续写下去,会发现当你研究懂一段源码以后,那种成就感真的很爽0.0
PS: 码字不易,但愿你们多多点赞哈,给小弟点动力T.T
参考:公众号-芋道源码