横云断岭 2020-02-20
目录
Spring 核心编程思想目录:https://www.cnblogs.com/binarylei/p/12290153.html
特别声明: Bean 完整创建过程,包括实例化、依赖注入、初始化阶段 。本文中 Bean 实例化指的是 Bean 对象的创建的第一阶段 - 实例化,不包括之后的属性注入、初始化。为了避免混淆,在此做一个约定,创建阶段指完整的对象创建过程,实例化阶段则单指第一阶段。Spring 构造器注入或工厂注入也是在实例化过程中完成的,之于第二个依赖注入指的是其它的所有注入方式,如 Settter 注入,字段注入等。
Bean 实例化大致可以分为以下场景:
本文重点分析以下方法:
beanFactory#instantiateUsingFactoryMethod:一般表示注解驱动( @Bean 注册),工厂方法实例化。委托给 ConstructorResolver#instantiateUsingFactoryMethod。
Bean 完整的创建过程,包括 Bean 实例化、属性注入、初始化全部操作。本文重点关注实例过程 createBeanInstance。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null; // 1. 缓存的提前初始化的FactoryBean,为什么会提前初始化。 if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // 2. 实例化Bean,构造器注入或工厂方法注入 if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } // 3. 属性注入、初始化 ... Object exposedObject = bean; populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); ... }
说明: 我们重点说一下为什么会在缓存中获取到提前部分初始化的 FactoryBean?
很明显这些 factoryBean 实例还需要进行属性注入、初始化等操作。我们知道,Spring 在提取对象类型时,FactoryBean 需要调用其 getObjectType 方法,此时就需要初始化 factoryBean 实例,但 Spring 为了减少提前初始化 Bean 产生的问题,只会将 factoryBean 提前实例化后缓存到 factoryBeanInstanceCache,当真正需要使用到 factoryBean 才进行完整的创建。事实上,只要我们进行依赖注入,调用 beanFactory#isTypeMatch 匹配对象类型,就会遍历所有注册的 beanDefinitionNames,从而实例化所有的 factoryBean 到 factoryBeanInstanceCache 中。
这就是 factoryBeanInstanceCache 中 factoryBean 实例的由来,具体见方法见 beanFactory#getSingletonFactoryBeanForTypeCheck,最终其实也是调用 beanFactory#createBeanInstance 方法。
createBeanInstance 方法用于 Bean 对象的实例化,包括工厂方法创建和构造器创建两种。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 1.1 确保此时beanClassName已经加载,当然注解驱动时不会设置beanClassName属性 Class<?> beanClass = resolveBeanClass(mbd, beanName); // 1.2 校验beanClass允许访问 if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(); } // 2. Supplier创建对象 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } // ========= 工厂方法实例化 ========= // 3. 工厂方法实例化,包括实例化工厂和静态工厂 if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // ========= 构造器实例化 ========= // 4. 快速实例化对象,所谓的快速实例化,实际上是说使用缓存 boolean resolved = false; boolean autowireNecessary = false; // 4.1 args: 外部化参数,只能当无外部参数时才使用缓存。不推荐使用外部化参数 if (args == null) { synchronized (mbd.constructorArgumentLock) { // 4.2 是否使用缓存,其中autowireNecessary表示是否使用有参构造器 // 无参时肯定不会解析,为false。有参时会解析,为true if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } // 4.3 使用缓存,其中autowireNecessary表示是否使用有参构造器 if (resolved) { if (autowireNecessary) { // 4.4 有参构造器实例化 return autowireConstructor(beanName, mbd, null, null); } else { // 4.5 无参构造器实例化 return instantiateBean(beanName, mbd); } } // 5. 到此,只能老老实实的解析,当然解析后会将解析后的构造器或参数缓存起来 // 5.1 是否指定了构造器,ibp#determineCandidateConstructors Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); // 5.2 构造器实例化 if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 5.3 不用管,默认都是 null。 ctors = mbd.getPreferredConstructors(); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, null); } // 5.4 无参构造器实例化 return instantiateBean(beanName, mbd); }
说明: createBeanInstance 方法在 bd.beanClass 校验后进行对象实例化,而 Supplier 实例化比较简单,工厂方法实例化又全部委托给了 instantiateUsingFactoryMethod 方法,基本上主要的功能就是,判断如何使用构造器实例化对象。
<bean id="beanA" class="com.binarylei.spring.ioc.BeanA" autowire="constructor"/>
。Spring 在对象实例化上进行了抽象,提供了 InstantiationStrategy 接口用于实例对象,两个实现类 SimpleInstantiationStrategy 和 CglibSubclassingInstantiationStrategy。
Spring 默认的实例化策略是 CglibSubclassingInstantiationStrategy,该类是为了解决 <replaced-method> 或 <lookup-method> 标签,在这种情况下,必须进行字节码提升才能实例化对象。通常我们不会用到这些标签,本文只会介绍常规的实例化方法,直接调用反射实例化对象,即其父类 SimpleInstantiationStrategy。
InstantiationStrategy 提供了三个方法,分别用于实例化无参构造器,有参构造器,工厂方法。
// 1. 无参构造器实例化 Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner); throws BeansException; // 2. 有参构造器实例化 Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, Constructor<?> ctor, Object... args) throws BeansException; // 3. 工厂方法实例化 Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, Object factoryBean, Method factoryMethod, Object... args) throws BeansException;
说明: SimpleInstantiationStrategy 实现都非常简单,无非是通过 Java 反射实例化对象。
注意:无参构造器是会缓存 bd.resolvedConstructorOrFactoryMethod。
无参实例化 instantiateBean 方法,本质是直接获取对象的默认构造器,通过反射创建对象,也就是调用 instantiationStrategy.instantiate 方法。
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { // 1. 调用无参构造器实例化对象 Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); BeanWrapper bw = new BeanWrapperImpl(beanInstance); // 2. 配置bw的类型转换器,依赖注入时可能需要对注入的属性值进行类型转换 initBeanWrapper(bw); return bw; }
autowireConstructor 和 instantiateUsingFactoryMethod 方法其实没有本质的区别,都是通过参数注入。autowireConstructor 通过构造器实例化,instantiateUsingFactoryMethod 通过特定的工厂方法实例化,如果将构造方法当作一种特殊的方法,那么这两种注入方式没有本质的区别。事实上,Spring 也是将这两种注入方式统一进行处理的。
autowireConstructor:传统方式,通过构造器实例化。委托给 ConstructorResolver#autowireConstructor。
instantiateUsingFactoryMethod:一般表示注解驱动( @Bean 注册),通过工厂方法实例化。委托给 ConstructorResolver#instantiateUsingFactoryMethod。
本文重点分析构造器注入 autowireConstructor 方法,了解构造器注入后,工厂注入基本上如出一辙。无论是构造器注入还是工厂方法注入都会面临如下问题:
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) { // 1. 使用缓存,快速实例化对象 Constructor<?> constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod; ArgumentsHolder argsToUse = mbd.resolvedConstructorArguments; // 非缓存,进行参数匹配 if (constructorToUse == null || argsToUse == null) { // 2. (非缓存)匹配无参构造器 if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { return ... } // 3. (非缓存)匹配有参构造器 for (Constructor<?> candidate : candidates) { } } return bw; }
说明: 构造器实例化对象,代码比较长。我会将其拆开,大致分为缓存匹配、无参构造器匹配,有参构造器匹配三步分。
只要对象实例化后,bd 就会缓存其构造方法或参数等信息用于快速实例化对象。缓存这一块比较简单,重要的弄清楚这些缓存变量的含义,以及什么时候缓存的?
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; } } } if (argsToResolve != null) { argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); } }
说明: 可以很清楚的看到外部化参数没有使用缓存,每次都需要重新解析。至于参数的解析 resolvePreparedArguments 会在下方进行分析。
无参构造器匹配也很简单,如果没有指定构造器,则对所有的构造器进行匹配。当只有一个无参构造器,且无论是外部化参数或配置参数都为空时,则使用无参构造器。
Constructor<?>[] candidates = chosenCtors; if (candidates == null) { Class<?> beanClass = mbd.getBeanClass(); candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors()); } if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { Constructor<?> uniqueCandidate = candidates[0]; if (uniqueCandidate.getParameterCount() == 0) { synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; mbd.constructorArgumentsResolved = true; mbd.resolvedConstructorArguments = EMPTY_ARGS; } bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS)); return bw; } }
说明: 无参构造器解析后,会缓存所有的变量,不会再次解析。最复杂的是有参构造器的解析。
有参构造器匹配比较复杂,但也是有迹可循的:
(1)实际参数解析
对于外部化参数就不多说了,我们重点说一下绝大多数场景,默认配置参数。首先,解析已有的配置参数;其次,根据构造器参数类型和参数名称从 Spring IoC 容器中解析剩余的参数。如果能成功解析,则命中该构造器。
// autowiring表示是否允许从 Spring IoC 容器查找依赖 boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); ConstructorArgumentValues resolvedValues = null; int minNrOfArgs; // 1.1 外部化参数,不需要解析 if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; // 1.2 默认配置参数,先解析已有的配置参数 } else { ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } AutowireUtils.sortConstructors(candidates); int minTypeDiffWeight = Integer.MAX_VALUE; Set<Constructor<?>> ambiguousConstructors = null; LinkedList<UnsatisfiedDependencyException> causes = null; for (Constructor<?> candidate : candidates) { int parameterCount = candidate.getParameterCount(); if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) { break; } if (parameterCount < minNrOfArgs) { continue; } ArgumentsHolder argsHolder; Class<?>[] paramTypes = candidate.getParameterTypes(); // 1.3 默认配置参数,如果配置参数不足,从Spring IoC中继续解析参数。如果能解析则匹配成功 if (resolvedValues != null) { try { String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount); if (paramNames == null) { ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } } argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1); } catch (UnsatisfiedDependencyException ex) { causes.add(ex); continue; } // 1.4 外部化参数,只需要参数个数相等即可。此时resolvedValues=null } else { if (parameterCount != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); } ... }
说明: 根据实际的参数解析匹配可用的构造器。
(2)权值计算
权重越小优先级越高。如果无法匹配或有多个权重相同的构造器,则抛出异常。constructorToUse 匹配
int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // 权重最高的构造器 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); }
说明: constructorToUse 表示权重最高的构造器,ambiguousConstructors 表示有多个权重最高的构造器。如果没有匹配的构造器(constructorToUse=null)或有多个权重相等的构造器(ambiguousConstructors!=null)都需要抛出异常。下面我们看一下权重的计算,以 getAssignabilityWeight 为例,权重值越小优先级越高。
// paramTypes 表示构造器或方法参数类型列表 public int getAssignabilityWeight(Class<?>[] paramTypes) { // 1. arguments表示解析后的参数 for (int i = 0; i < paramTypes.length; i++) { if (!ClassUtils.isAssignableValue(paramTypes[i], this.arguments[i])) { return Integer.MAX_VALUE; } } // 2. arguments表示解析前的参数,如配置参数 for (int i = 0; i < paramTypes.length; i++) { if (!ClassUtils.isAssignableValue(paramTypes[i], this.rawArguments[i])) { return Integer.MAX_VALUE - 512; } } return Integer.MAX_VALUE - 1024; }
(3)实例化对象
// 1. 缓存解析后的构造器和参数 if (explicitArgs == null && argsHolderToUse != null) { argsHolderToUse.storeCache(mbd, constructorToUse); } // 2. 调用InstantiationStrategy实例化参数 bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse)); return bw;
说明: 在构造器实例化对象开始前,第一步就是从 bd 缓存中快速实例化对象。其中无参构造器已经在匹配无参构造器时缓存,此时需要缓存有参构造器匹配的变量。
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; } } }
在 ArgumentsHolder 对象中有三个变量,都表示参数:
arguments:已经解析后的参数,不需要再进行解析,直接可以注入。
preparedArguments:已部分解析后的参数,这个主要是用来解析注入的实际参数。
rawArguments:原始的参数,这个主要是用来计算构造器的权重。
到目前为止,ConstructorResolver#autowireConstructor 构造器实例化已经分析完毕,autowireConstructor 方法最主要的两个功能就是解析参数,匹配构造器。构造器的匹配我们已经分析过了,接下为是遗留下来的参数解析。
ConstructorResolver 提供了以下方法进行参数解析:
resolveConstructorArguments 方法解析默认的配置参数 mbd.constructorArgumentValues。
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) { TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); TypeConverter converter = (customConverter != null ? customConverter : bw); BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter); int minNrOfArgs = cargs.getArgumentCount(); for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) { ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue(); if (valueHolder.isConverted()) { resolvedValues.addIndexedArgumentValue(index, valueHolder); } else { // 核心代码就这么一句,将参数解析全部委托给valueResolver Object resolvedValue = valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue()); ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName()); resolvedValueHolder.setSource(valueHolder); resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder); } } // 泛型参数解析 ... return minNrOfArgs; }
说明: resolveConstructorArguments 方法的核心代码就一句,valueResolver.resolveValueIfNecessary。看到 BeanDefinitionValueResolver 你是否会感到很熟悉呢?在 setter 等注入时,调用 beanFactory#applyPropertyValues 方法也需要解析 mbd.pvs 参数,同样也会用到 valueResolver.resolveValueIfNecessary 来解析配置参数,不管是那种注入方式,参数的解析都是一样的。
createArgumentArray 方法很长,其实逻辑反而并不复杂,遍历构造器的所有参数,先到 resolveConstructorArguments 方法已经解析过的参数中查找参数,如果查找到就使用配置的参数。当然如果查找不到,这时就判断是否允许自行注入,如果允许,则从 Spring IoC 容器中查找依赖,即调用 beanFactory#resolveDependency 方法。
/** * @param resolvedValues 表示bd.constructorArgumentValues中已经解析的参数 * @param paramTypes 表示当前的构造器或方法的参数类型列表 * @param paramNames 方法的参数名称 * @param executable 方法或构造器 * @param autowiring 是否采用构造器自动注入,如果是则会从Spring IoC容器中查找参数 * @param fallback 如果已经有多个构造器或方法匹配,则fallback=false */ private ArgumentsHolder createArgumentArray( String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues, BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable, boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException { TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); TypeConverter converter = (customConverter != null ? customConverter : bw); ArgumentsHolder args = new ArgumentsHolder(paramTypes.length); Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length); Set<String> autowiredBeanNames = new LinkedHashSet<>(4); for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) { Class<?> paramType = paramTypes[paramIndex]; String paramName = (paramNames != null ? paramNames[paramIndex] : ""); // 1. 从默认的配置参数中查找参数 ConstructorArgumentValues.ValueHolder valueHolder = null; if (resolvedValues != null) { // 1.1 查找已经有参数,可以根据参数的索引或名称查找 valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders); // 1.2 如果不是自动注入,则要想方设法查找参数,因为自动注入还可以从容器中查找参数 if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) { valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders); } } // 2. 已经从配置该参数,这部分代码省略 if (valueHolder != null) { ... // 3. 没有配置该参数,尝试从Spring IoC容器中查找 } else { MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex); if (!autowiring) { throw new UnsatisfiedDependencyException(); } // 3.1 核心代码,调用 beanFactory#resolveDependency Object autowiredArgument = resolveAutowiredArgument( methodParam, beanName, autowiredBeanNames, converter, fallback); args.rawArguments[paramIndex] = autowiredArgument; args.arguments[paramIndex] = autowiredArgument; // 3.2 自动注入标记位 args.preparedArguments[paramIndex] = autowiredArgumentMarker; args.resolveNecessary = true; } } for (String autowiredBeanName : autowiredBeanNames) { this.beanFactory.registerDependentBean(autowiredBeanName, beanName); } return args; }
说明: 对于构造器中的参数,如果在配置参数中命中,使用配置的参数。对于没有命中的参数,如果允许自动注入,则调用 beanFactory#resolveDependency 从容器中查找。
resolvePreparedArguments 方法是对 mbd.preparedConstructorArguments 中还需要解析的参数调用 BeanDefinitionValueResolver#resolveValueIfNecessary 进行解析。
private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, Executable executable, Object[] argsToResolve, boolean fallback) { TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); TypeConverter converter = (customConverter != null ? customConverter : bw); BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter); Class<?>[] paramTypes = executable.getParameterTypes(); Object[] resolvedArgs = new Object[argsToResolve.length]; for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) { Object argValue = argsToResolve[argIndex]; MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex); // createArgumentArray 方法设置的自动注入标记 if (argValue == autowiredArgumentMarker) { argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback); } else if (argValue instanceof BeanMetadataElement) { argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue); } else if (argValue instanceof String) { argValue = this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd); } Class<?> paramType = paramTypes[argIndex]; resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam); } return resolvedArgs; }
说明: 核心就是 BeanDefinitionValueResolver#resolveValueIfNecessary,其实所以的类型注入最终都逃不离 beanFactory#resolveDependency 这个最基础的方法,而这个方法的核心是 Spring 的类型自省。
其实也了解了构造器实例化 autowireConstructor 之后,instantiateUsingFactoryMethod 方法基本大同小异。同样是匹配工厂方法,解析参数。
每天用心记录一点点。内容也许不重要,但习惯很重要!