目录
- 【1】前言
- 【2】对于实例化的疑问
- 【3】推断构造方法源码分析
针对实例化过程中会做什么的分析,其中主要的是怎么推断出构造方法,怎么进行匹配
【1】前言
实例化这一步便是在doCreateBean方法的 instanceWrapper = createBeanInstance(beanName, mbd, args);这段代码中。
【2】对于实例化的疑问
对于Spring中的beanBeanDefinition,需要通过实例化得到一个bean对象才会被放入容器中,而实例化就需要用到构造方法。
分析:一个类存在多个构造方法,那么Spring进行实例化时,该如何去确定到底用哪个构造方法呢?
1. 如果开发者指定了想要使用的构造方法,那么就用这个构造方法。
2. 如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构造方法。
3. 如果开发者也没有让Spring自动去选择构造方法,则Spring利用无参构造方法,如果没有无参构造方法,则报错。
开发者可以通过什么方式来指定使用哪个构造方法呢?
1.通过xml中的<constructor-arg>标签,这个标签表示构造方法参数,所以可以根据这个确定想要使用的构造方法的参数个数,从而确定想要使用的构造方法
2.通过@Autowired注解,@Autowired注解可以写在构造方法上,所以哪个构造方法上写了@Autowired注解,表示开发者想使用哪个构造方法,当然,它和第一个方式的不同点是,通过xml的方式,我们直接指定了构造方法的参数值,而通过@Autowired注解的方式,需要Spring通过byType+byName的方式去找到符合条件的bean作为构造方法的参数值。
3.如果Bean为注解@Lazy修饰的或者非单例的,可以通过getBean方法设置构造方法的入参,达到指定构造方法的效果。如,applicationContext.getBean("BeanDemo", new CircularRefA());【同理,获取beanDefinition,使用beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new CircularRefA());指定构造方法参数】
【3】推断构造方法源码分析
1.主体代码逻辑
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { | |
/** | |
* ----------0,校验部分------------ | |
*/ | |
ClassresolveBeanClass(mbd, beanName); | > beanClass =|
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()); | |
} | |
/** | |
* ----------1,通过Supplier实例化部分------------ | |
*/ | |
// BeanDefinition中添加了Supplier,则调用Supplier来得到对象 | |
SuppliergetInstanceSupplier(); | > instanceSupplier = mbd.|
if (instanceSupplier != null) { | |
return obtainFromSupplier(instanceSupplier, beanName); | |
} | |
/** | |
* ----------2,通过工厂方法实例化部分------------ | |
*/ | |
// @Bean对应的BeanDefinition | |
if (mbd.getFactoryMethodName() != null) { | |
return instantiateUsingFactoryMethod(beanName, mbd, args); | |
} | |
/** | |
* ----------3,用合适的构造函数实例化部分------------ | |
* | |
* 一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器。 | |
* 原型的BeanDefinition,会多次来创建Bean。故在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,避免再次创建相同bean时再次解析(节约时间) | |
*/ | |
boolean resolved = false; //对构造器是否缓存了 | |
boolean autowireNecessary = false; //缓存的构造器是否有参数 | |
if (args == null) { | |
synchronized (mbd.constructorArgumentLock) { | |
if (mbd.resolvedConstructorOrFactoryMethod != null) { | |
resolved = true; | |
// autowireNecessary表示有没有必要要进行注入,比如当前BeanDefinition用的是无参构造方法,那么autowireNecessary为false,否则为true,表示需要给构造方法参数注入值 | |
autowireNecessary = mbd.constructorArgumentsResolved; | |
} | |
} | |
} | |
if (resolved) { | |
// 如果确定了当前BeanDefinition的构造方法,那么看是否需要进行对构造方法进行参数的依赖注入(构造方法注入) | |
if (autowireNecessary) { | |
// 方法内会拿到缓存好的构造方法的入参 | |
return autowireConstructor(beanName, mbd, null, null); | |
} | |
else { | |
// 构造方法已经找到了,但是没有参数,那就表示是无参,直接进行实例化 | |
return instantiateBean(beanName, mbd); | |
} | |
} | |
//没有缓存,从bean后置处理器中为自动装配寻找构造方法 | |
ConstructordetermineConstructorsFromBeanPostProcessors(beanClass, beanName); | >[] ctors =|
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || | |
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { | |
return autowireConstructor(beanName, mbd, ctors, args); | |
} | |
// 找出最合适的默认构造方法 | |
ctors = mbd.getPreferredConstructors(); | |
if (ctors != null) { | |
// 构造函数自动注入 | |
return autowireConstructor(beanName, mbd, ctors, null); | |
} | |
/** | |
* ----------4,使用默认构造函数构造部分------------ | |
*/ | |
// 不匹配以上情况,则直接使用无参构造方法 | |
return instantiateBean(beanName, mbd); | |
} |
代码说明
createBeanInstance() 方法是 spring 实例化 bean 的核心代码,它根据不同的情况会调用四种实例化方法:
1)obtainFromSupplier() :通过 Supplier 实例化
2)instantiateUsingFactoryMethod():通过工厂方法实例化
3)autowireConstructor():用合适的构造函数实例化
4)instantiateBean():用无参构造函数实例化
2.局部分析代码
1)通过Supplier实例化部分解析
代码
// BeanDefinition中添加了Supplier,则调用Supplier来得到对象 | |
Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); | |
if (instanceSupplier != null) { | |
return obtainFromSupplier(instanceSupplier, beanName); | |
} |
说明
Spring提供的一种机制,虽然不常用,通过设置实现Supplier接口的类,返回一个另一种的对象,类似于FactoryBean的感觉。示例:
//在beanDefinition阶段设置好 | |
beanDefinition.setBeanClass(Student.class); | |
beanDefinition.setInstanceSupplier(new Supplier<Object>() { | |
public Object get() { | |
return new UserServiceImpl1(); | |
} | |
}); | |
//容器启动后尝试获取验证 | |
applicationContext.getBean("student"); //返回new UserServiceImpl1()对象 |
2)通过工厂方法实例化部分针(同时也是@Bean注解的处理)解析【如果存疑可以查看注解@Bean解析】
代码块
// @Bean对应的BeanDefinition | |
if (mbd.getFactoryMethodName() != null) { | |
return instantiateUsingFactoryMethod(beanName, mbd, args); | |
} |
代码深入部分:instantiateUsingFactoryMethod方法解析
protected BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, { Object[] explicitArgs) | |
// 使用factoryBean来实例化对象 | |
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs); | |
} | |
//ConstructorResolver类#instantiateUsingFactoryMethod方法 | |
//省略日志与异常 | |
public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, { Object[] explicitArgs) | |
BeanWrapperImpl bw = new BeanWrapperImpl(); | |
this.beanFactory.initBeanWrapper(bw); | |
Object factoryBean; | |
Class<?> factoryClass; | |
boolean isStatic; | |
//通过beanDefinition获取到factoryBeanName ,实际就是@Bean注解的方法所在的configuration类 | |
String factoryBeanName = mbd.getFactoryBeanName(); | |
//表示非静态方法 | |
if (factoryBeanName != null) { | |
if (factoryBeanName.equals(beanName)) { | |
throw new BeanDefinitionStoreException(...); | |
} | |
factoryBean = this.beanFactory.getBean(factoryBeanName); | |
// 该mbd已经创建过了【代表这个逻辑已经走过了】 | |
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { | |
throw new ImplicitlyAppearedSingletonException(); | |
} | |
factoryClass = factoryBean.getClass(); | |
isStatic = false; | |
} | |
else {//表示静态方法 | |
// It's a static factory method on the bean class. | |
if (!mbd.hasBeanClass()) { | |
throw new BeanDefinitionStoreException(...); | |
} | |
factoryBean = null; | |
factoryClass = mbd.getBeanClass(); | |
isStatic = true; | |
} | |
Method factoryMethodToUse = null; | |
ArgumentsHolder argsHolderToUse = null; | |
Object[] argsToUse = null; | |
//如果在调用getBean方法时有传参,那就用传的参作为@Bean注解的方法(工厂方法)的参数, 一般懒加载的bean才会传参,启动过程就实例化的实际上都没有传参 | |
if (explicitArgs != null) { | |
argsToUse = explicitArgs; | |
} | |
else { | |
Object[] argsToResolve = null; | |
synchronized (mbd.constructorArgumentLock) { | |
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod; | |
//不为空表示已经使用过工厂方法,现在是再次使用工厂方法, 一般原型模式和Scope模式采用的上,直接使用该工厂方法和缓存的参数 | |
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) { | |
// Found a cached factory method... | |
argsToUse = mbd.resolvedConstructorArguments; | |
if (argsToUse == null) { | |
argsToResolve = mbd.preparedConstructorArguments; | |
} | |
} | |
} | |
if (argsToResolve != null) { | |
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true); | |
} | |
} | |
// 调用getBean方法没有传参,同时也是第一次使用工厂方法 | |
if (factoryMethodToUse == null || argsToUse == null) { | |
factoryClass = ClassUtils.getUserClass(factoryClass); | |
// 获取configuration类的所有候选方法 | |
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); | |
List<Method> candidateList = new ArrayList<>(); | |
for (Method candidate : rawCandidates) { | |
// 查找到与工厂方法同名的候选方法,即有@Bean的同名方法 | |
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { | |
candidateList.add(candidate); | |
} | |
} | |
//当与工厂方法同名的候选方法只有一个,且调用getBean方法时没有传参,且没有缓存过参数,直接通过调用实例化方法执行该候选方法 | |
if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { | |
Method uniqueCandidate = candidateList.get(0); | |
if (uniqueCandidate.getParameterCount() == 0) { | |
mbd.factoryMethodToIntrospect = uniqueCandidate; | |
synchronized (mbd.constructorArgumentLock) { | |
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; | |
mbd.constructorArgumentsResolved = true; | |
mbd.resolvedConstructorArguments = EMPTY_ARGS; | |
} | |
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS)); | |
return bw; | |
} | |
} | |
Method[] candidates = candidateList.toArray(new Method[0]); | |
// 有多个与工厂方法同名的候选方法时,进行排序。public的方法会往前排,然后参数个数多的方法往前排 | |
AutowireUtils.sortFactoryMethods(candidates); | |
ConstructorArgumentValues resolvedValues = null; | |
boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); | |
int minTypeDiffWeight = Integer.MAX_VALUE; | |
Set<Method> ambiguousFactoryMethods = null; | |
int minNrOfArgs; | |
// 如果调用getBean方法时有传参,那么工厂方法最少参数个数要等于传参个数 | |
if (explicitArgs != null) { | |
minNrOfArgs = explicitArgs.length; | |
} | |
else { | |
//如果getBean的时候没有传参,如果BeanDefinition中有设置,则从BeanDefinition中获取 | |
if (mbd.hasConstructorArgumentValues()) { | |
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); | |
resolvedValues = new ConstructorArgumentValues(); | |
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); | |
} | |
else { | |
minNrOfArgs = 0; | |
} | |
} | |
LinkedList<UnsatisfiedDependencyException> causes = null; | |
for (Method candidate : candidates) { | |
Class<?>[] paramTypes = candidate.getParameterTypes(); | |
if (paramTypes.length >= minNrOfArgs) { | |
ArgumentsHolder argsHolder; | |
if (explicitArgs != null) { | |
// Explicit arguments given -> arguments length must match exactly. | |
if (paramTypes.length != explicitArgs.length) { | |
continue; | |
} | |
argsHolder = new ArgumentsHolder(explicitArgs); | |
} | |
else { | |
// Resolved constructor arguments: type conversion and/or autowiring necessary. | |
try { | |
String[] paramNames = null; | |
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); | |
if (pnd != null) { | |
paramNames = pnd.getParameterNames(candidate); | |
} | |
//当传入的参数为空,需要根据工厂方法的参数类型注入相应的bean | |
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, | |
paramTypes, paramNames, candidate, autowiring, candidates.length == 1); | |
} | |
catch (UnsatisfiedDependencyException ex) { | |
if (logger.isTraceEnabled()) { | |
logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex); | |
} | |
// Swallow and try next overloaded factory method. | |
if (causes == null) { | |
causes = new LinkedList<>(); | |
} | |
causes.add(ex); | |
continue; | |
} | |
} | |
//计算工厂方法的权重 | |
int typeDiffWeight = (mbd.isLenientConstructorResolution() ? | |
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); | |
// Choose this factory method if it represents the closest match. | |
if (typeDiffWeight < minTypeDiffWeight) { | |
/* | |
* 当权重小时,重新设置factoryMethodToUse 和argsHolderToUse ,argsToUse , | |
* 并把当前权重值设置为最小权重值,等待遍历的下一个候选工厂方法比对, | |
* 并且将ambiguousFactoryMethods (表示有含糊同样权重的候选方法)设置为空 | |
* */ | |
factoryMethodToUse = candidate; | |
argsHolderToUse = argsHolder; | |
argsToUse = argsHolder.arguments; | |
minTypeDiffWeight = typeDiffWeight; | |
ambiguousFactoryMethods = null; | |
} | |
/* | |
* 当遍历到下一个候选方法的时候,已经设置了factoryMethodToUse 且权重值与上一次的最小权重值相等时, | |
* ambiguousFactoryMethods填值,这个ambiguousFactoryMethods不为空表示有两个候选方法的最小权重相等, | |
* spring无法匹配出最适合的工厂方法,如果再继续往下遍历候选器,有更小的权重值, | |
* 那ambiguousFactoryMethods会再次被设置为空 | |
* */ | |
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight && | |
!mbd.isLenientConstructorResolution() && | |
paramTypes.length == factoryMethodToUse.getParameterCount() && | |
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) { | |
if (ambiguousFactoryMethods == null) { | |
ambiguousFactoryMethods = new LinkedHashSet<>(); | |
ambiguousFactoryMethods.add(factoryMethodToUse); | |
} | |
ambiguousFactoryMethods.add(candidate); | |
} | |
} | |
} | |
if (factoryMethodToUse == null) { | |
if (causes != null) { | |
UnsatisfiedDependencyException ex = causes.removeLast(); | |
for (Exception cause : causes) { | |
this.beanFactory.onSuppressedException(cause); | |
} | |
throw ex; | |
} | |
List<String> argTypes = new ArrayList<>(minNrOfArgs); | |
if (explicitArgs != null) { | |
for (Object arg : explicitArgs) { | |
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null"); | |
} | |
} | |
else if (resolvedValues != null) { | |
Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount()); | |
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values()); | |
valueHolders.addAll(resolvedValues.getGenericArgumentValues()); | |
for (ValueHolder value : valueHolders) { | |
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) : | |
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null")); | |
argTypes.add(argType); | |
} | |
} | |
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes); | |
throw new BeanCreationException(...); | |
} | |
//返回类型不能为void | |
else if (void.class == factoryMethodToUse.getReturnType()) { | |
throw new BeanCreationException(...); | |
} | |
//存在含糊的两个工厂方法,不知选哪个 | |
else if (ambiguousFactoryMethods != null) { | |
throw new BeanCreationException(...); | |
} | |
if (explicitArgs == null && argsHolderToUse != null) { | |
mbd.factoryMethodToIntrospect = factoryMethodToUse; | |
argsHolderToUse.storeCache(mbd, factoryMethodToUse); | |
} | |
} | |
//去实例化 | |
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse)); | |
return bw; | |
} |
3)用合适的构造函数实例化部分解析
boolean resolved = false; //对构造器是否缓存了 | |
boolean autowireNecessary = false; //缓存的构造器是否有参数 | |
//判断是否有传参,因为getBean方法可以通过传参指定构造方法参数类型来进行匹配(故这种对于参数的不确定是不能缓存的) | |
if (args == null) { | |
synchronized (mbd.constructorArgumentLock) { | |
if (mbd.resolvedConstructorOrFactoryMethod != null) { | |
resolved = true; | |
// autowireNecessary表示有没有必要要进行注入,比如当前BeanDefinition用的是无参构造方法,那么autowireNecessary为false,否则为true,表示需要给构造方法参数注入值 | |
autowireNecessary = mbd.constructorArgumentsResolved; | |
} | |
} | |
} | |
if (resolved) { | |
// 如果确定了当前BeanDefinition的构造方法,那么看是否需要进行对构造方法进行参数的依赖注入(构造方法注入) | |
if (autowireNecessary) { | |
// 方法内会拿到缓存好的构造方法的入参 | |
return autowireConstructor(beanName, mbd, null, null); | |
} | |
else { | |
// 构造方法已经找到了,但是没有参数,那就表示是无参,直接进行实例化 | |
return instantiateBean(beanName, mbd); | |
} | |
} | |
//没有缓存,从bean后置处理器中为自动装配寻找构造方法 | |
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); | |
//存在推断出来的构造方法集合 | |
//BeanDefinition被设置为AUTOWIRE_CONSTRUCTOR | |
//BeanDefinition指定了构造方法参数值 | |
//getBean的时候传入了构造方法参数值 | |
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || | |
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { | |
return autowireConstructor(beanName, mbd, ctors, args); | |
} | |
// 找出最合适的默认构造方法 | |
ctors = mbd.getPreferredConstructors(); | |
if (ctors != null) { | |
// 构造函数自动注入 | |
return autowireConstructor(beanName, mbd, ctors, null); | |
} |
代码说明
【1】针对determineConstructorsFromBeanPostProcessors方法分析
代码展示
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors( Class<?> beanClass, String beanName) throws BeansException { | |
//如果类不为null,且存在InstantiationAwareBeanPostProcessor接口的处理器【其实用的不是它,而是他的子接口SmartInstantiationAwareBeanPostProcessor】 | |
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) { | |
for (BeanPostProcessor bp : getBeanPostProcessors()) { | |
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { | |
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; | |
//真正存在实现的类是AutowiredAnnotationBeanPostProcessor类 | |
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName); | |
if (ctors != null) { | |
return ctors; | |
} | |
} | |
} | |
} | |
return null; | |
} | |
//AutowiredAnnotationBeanPostProcessor类#determineCandidateConstructors方法 | |
//日志和异常的输出会被省略 | |
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException { | |
// 判断是否检测过 | |
if (!this.lookupMethodsChecked.contains(beanName)) { | |
try { | |
// 遍历目标类中的method,查看是否写了@Lookup方法 | |
ReflectionUtils.doWithMethods(beanClass, method -> { | |
Lookup lookup = method.getAnnotation(Lookup.class); | |
if (lookup != null) { | |
Assert.state(this.beanFactory != null, "No BeanFactory available"); | |
// 将当前method封装成LookupOverride并设置到BeanDefinition的methodOverrides中 | |
LookupOverride override = new LookupOverride(method, lookup.value()); | |
try { | |
RootBeanDefinition mbd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName); | |
mbd.getMethodOverrides().addOverride(override); | |
} | |
catch (NoSuchBeanDefinitionException ex) { | |
throw new BeanCreationException(beanName,"..."); | |
} | |
} | |
}); | |
} | |
catch (IllegalStateException ex) { | |
throw new BeanCreationException(beanName, "...", ex); | |
} | |
this.lookupMethodsChecked.add(beanName); | |
} | |
//先从缓存中获取,看之前有没有找过 | |
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass); | |
//缓存中没有 | |
if (candidateConstructors == null) { | |
// 加锁,开始寻找 | |
synchronized (this.candidateConstructorsCache) { | |
//再次从缓存中获取,看被阻塞的时候没有有线程已经找好了存在缓存中(加锁并双重判断的常规做法) | |
candidateConstructors = this.candidateConstructorsCache.get(beanClass); | |
if (candidateConstructors == null) { | |
Constructor<?>[] rawCandidates; | |
try { | |
// 拿到所有的构造方法 | |
rawCandidates = beanClass.getDeclaredConstructors(); | |
} | |
catch (Throwable ex) { | |
throw new BeanCreationException(beanName, "...", ex); | |
} | |
List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length); | |
// 用来记录required为true的构造方法,一个类中只能有一个required为true的构造方法 | |
Constructor<?> requiredConstructor = null; | |
// 用来记录默认无参的构造方法 | |
Constructor<?> defaultConstructor = null; | |
// kotlin相关,不用管 | |
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass); | |
int nonSyntheticConstructors = 0; | |
// 遍历每个构造方法 | |
for (Constructor<?> candidate : rawCandidates) { | |
if (!candidate.isSynthetic()) { | |
// 记录一下普通的构造方法 | |
nonSyntheticConstructors++; | |
} | |
else if (primaryConstructor != null) { | |
continue; | |
} | |
// 当前遍历的构造方法是否写了@Autowired | |
AnnotationAttributes ann = findAutowiredAnnotation(candidate); | |
//没有@Autowired注解的情况 | |
if (ann == null) { | |
// 如果beanClass是代理类,则得到被代理的类的类型 | |
Class<?> userClass = ClassUtils.getUserClass(beanClass); | |
if (userClass != beanClass) { | |
try { | |
//寻找被代理的类上的构造方法有没有@Autowired注解 | |
Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes()); | |
ann = findAutowiredAnnotation(superCtor); | |
} | |
catch (NoSuchMethodException ex) {} | |
} | |
} | |
/** | |
* 构造方法如果有@Autowired注解,最后的操作是candidates.add(candidate),但如果出现两种情况会抛出异常 | |
* a、如果之前有遍历过@Autowired的构造器,即requiredConstructor不为空 | |
* b、如果当前的@Autowired的required属性为true,不管之前遍历过的@Autowired属性是true还是false | |
*/ | |
if (ann != null) { | |
// 整个类中如果有一个required为true的构造方法,那就不能有其他的加了@Autowired的构造方法 | |
if (requiredConstructor != null) { | |
throw new BeanCreationException(...); | |
} | |
//获取该方法上的@Autowired注解的required属性 | |
boolean required = determineRequiredStatus(ann); | |
if (required) { | |
if (!candidates.isEmpty()) { | |
throw new BeanCreationException(...); | |
} | |
requiredConstructor = candidate; | |
} | |
// 记录所有加了@Autowired的构造方法,不管required是true还是false,如果默认无参的构造方法上也加了@Autowired,那么也会加到candidates中 | |
candidates.add(candidate); | |
} | |
else if (candidate.getParameterCount() == 0) { //没有注解且参数个数为0【即无参】 | |
// 记录唯一一个无参的构造方法 | |
defaultConstructor = candidate; | |
} | |
//但是这里没有处理:有可能存在有参、并且没有添加@Autowired的构造方法。 | |
} | |
//存储有@Autowired注解的构造方法的集合不为空 | |
if (!candidates.isEmpty()) { | |
// 如果不存在一个required为true的构造方法,则所有required为false的构造方法和无参构造方法都是合格的 | |
if (requiredConstructor == null) { | |
if (defaultConstructor != null) { | |
//无参构造方法也添加到集合中 | |
candidates.add(defaultConstructor); | |
} | |
else if (candidates.size() == 1 && logger.isInfoEnabled()) { | |
logger.info(...); | |
} | |
} | |
// 转为数组 | |
candidateConstructors = candidates.toArray(new Constructor<?>[0]); | |
} | |
// 没有添加了@Autowired注解的构造方法,并且类中只有一个构造方法,并且是有参的 | |
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) { | |
candidateConstructors = new Constructor<?>[] {rawCandidates[0]}; | |
} | |
// primaryConstructor不用管 | |
else if (nonSyntheticConstructors == 2 && primaryConstructor != null && defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) { | |
candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor}; | |
} | |
// primaryConstructor不用管 | |
else if (nonSyntheticConstructors == 1 && primaryConstructor != null) { candidateConstructors = new Constructor<?>[] {primaryConstructor}; | |
} | |
else { | |
// 如果有多个有参、并且没有添加@Autowired的构造方法,是会返回空的 | |
candidateConstructors = new Constructor<?>[0]; | |
} | |
//将结果存入缓存 | |
this.candidateConstructorsCache.put(beanClass, candidateConstructors); | |
} | |
} | |
} | |
//有候选构造器则返回,没有返回null | |
return (candidateConstructors.length > 0 ? candidateConstructors : null); | |
} | |
返回结果预测: | |
没有加了 | 注解的构造方法|
有多个构造方法 --》 返回null | |
只有一个有参的构造方法 --》 返回此构造方法 | |
只有一个无参的构造方法 --》 返回null | |
存在加了 | 注解的构造方法|
只有一个required为true的构造方法 --》 返回此构造方法 | |
有多个required为true的构造方法 --》 抛异常 | |
有一个required为true和其他的required为false的构造方法 --》 视情况而定,可能会抛异常,可能会返回带注解的构造方法 | |
没有required为true的构造方法 --》 返回所有required为false的构造方法以及无参构造方法 |
发现说明
1.在多个构造方法上添加@Autowired注解会发生什么?
(1)因为@Autowired注解的required属性默认为true,而根据源码展示,如果有一个构造方法上的@Autowired注解的required为true,那么后面的其他的构造方法不管@Autowired注解的required属性是什么都会报错。
(2)故如果要在多个构造方法上添加@Autowired注解,那么必须将他们的required属性设置为false。(这种更安全)
(3)要么就是将@Autowired注解的required属性设置为true的构造方法放到最后【仅限一个】
4)autowireConstructor方法分析
代码展示
protected BeanWrapper autowireConstructor( String beanName, RootBeanDefinition mbd, { Constructor<?>[] ctors, Object[] explicitArgs) | |
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs); | |
} | |
public ConstructorResolver(AbstractAutowireCapableBeanFactory beanFactory) { | |
this.beanFactory = beanFactory; | |
this.logger = beanFactory.getLogger(); | |
} | |
//ConstructorResolver类#autowireConstructor方法 | |
//省略一些异常和日志 | |
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, { Constructor<?>[] chosenCtors, Object[] explicitArgs) | |
// 实例化BeanWrapper,是包装bean的容器 | |
BeanWrapperImpl bw = new BeanWrapperImpl(); | |
this.beanFactory.initBeanWrapper(bw); | |
Constructor<?> constructorToUse = null; | |
ArgumentsHolder argsHolderToUse = null; | |
Object[] argsToUse = null; | |
// 如果getBean()传入了args,那构造方法要用的入参就直接确定好了 | |
if (explicitArgs != null) { | |
argsToUse = explicitArgs; | |
} | |
else { | |
// 如果getBean()没有传入了参数 | |
Object[] argsToResolve = null; | |
synchronized (mbd.constructorArgumentLock) { | |
// 尝试从缓存中获取构造方法 | |
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod; | |
if (constructorToUse != null && mbd.constructorArgumentsResolved) { | |
// 从缓存中找到了构造器,那么继续从缓存中寻找缓存的构造器参数 | |
argsToUse = mbd.resolvedConstructorArguments; | |
if (argsToUse == null) { | |
// 缓存没有的话,那就获取BeanDefinition指定的那些参数【可以没有指定】 | |
argsToResolve = mbd.preparedConstructorArguments; | |
} | |
} | |
} | |
//argsToResolve不为空,即之前获取到了参数【是从BeanDefinition指定的】要解析配置的参数 | |
if (argsToResolve != null) { | |
// 解析参数类型,比如将配置的String类型转换为list、boolean等类型 | |
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); | |
} | |
} | |
// 如果没有确定要使用的构造方法,或者确定了构造方法但是所要传入的参数值没有确定 | |
if (constructorToUse == null || argsToUse == null) { | |
// 拿到传入的构造器数组 | |
Constructor<?>[] candidates = chosenCtors; | |
//数组为空 | |
if (candidates == null) { | |
Class<?> beanClass = mbd.getBeanClass(); | |
try { | |
//使用public的构造器(默认)或者所有构造器 | |
candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors()); | |
} | |
catch (Throwable ex) { throw new BeanCreationException(...); } | |
} | |
// 如果只有一个候选构造方法,并且没有指定所要使用的构造方法参数值,并且该构造方法是无参的,那就直接用这个无参构造方法进行实例化了 | |
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; | |
} | |
} | |
//需要解析构造函数标志(当构造方法数组不为空,或是自动装配构造函数时) | |
boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); | |
ConstructorArgumentValues resolvedValues = null; | |
// 确定要选择的构造方法的参数个数的最小值,后续判断候选构造方法的参数个数如果小于minNrOfArgs,则直接pass掉 | |
int minNrOfArgs; | |
if (explicitArgs != null) { | |
//如果直接传了构造方法参数值,那么所用的构造方法的参数个数肯定不能少于 | |
minNrOfArgs = explicitArgs.length; | |
} | |
else { | |
// 提取BeanDefinition中的配置的构造函数参数 | |
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); | |
// 用于承载解析后的构造函数参数的值 | |
resolvedValues = new ConstructorArgumentValues(); | |
// 能解析到的参数个数 | |
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); | |
} | |
// 排序给定的构造函数,public的构造函数优先,参数数量降序 | |
AutowireUtils.sortConstructors(candidates); | |
int minTypeDiffWeight = Integer.MAX_VALUE; | |
Set<Constructor<?>> ambiguousConstructors = null; | |
LinkedList<UnsatisfiedDependencyException> causes = null; | |
for (Constructor<?> candidate : candidates) { | |
Class<?>[] paramTypes = candidate.getParameterTypes(); | |
// 如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数参数个数则终止,前面已经经过了排序操作 | |
if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) { | |
break; | |
} | |
if (paramTypes.length < minNrOfArgs) { | |
// 参数个数不相等 | |
continue; | |
} | |
ArgumentsHolder argsHolder; | |
// 没有通过getBean()指定构造方法参数值 | |
if (resolvedValues != null) { | |
try { | |
// 有参数则根据值构造对应参数类型的参数 | |
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length); | |
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) { | |
// 当前正在遍历的构造方法找不到可用的入参对象,记录一下 | |
if (causes == null) { | |
causes = new LinkedList<>(); | |
} | |
causes.add(ex); | |
continue; | |
} | |
} | |
else { | |
// 在调getBean方法是传入了参数值,那就表示只能用对应参数个数的构造方法 | |
if (paramTypes.length != explicitArgs.length) { | |
continue; | |
} | |
// 构造函数没有参数的情况 | |
argsHolder = new ArgumentsHolder(explicitArgs); | |
} | |
// 当前遍历的构造方法所需要的入参对象都找到了,根据参数类型和找到的参数对象计算出来一个匹配值,值越小越匹配(Lenient表示宽松模式) | |
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); | |
} | |
} | |
// 遍历结束 | |
// 如果没有可用的构造方法,就取记录的最后一个异常并抛出 | |
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(...); | |
} | |
if (explicitArgs == null && argsHolderToUse != null) { | |
// 将解析的构造函数加入缓存 | |
argsHolderToUse.storeCache(mbd, constructorToUse); | |
} | |
} | |
// 将构造的实例加入BeanWrapper中 | |
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse)); | |
return bw; | |
} |
发现说明
1.autowireConstructor()大体流程
(1)先检查是否指定了具体的构造方法和构造方法参数值,或者在BeanDefinition中缓存了具体的构造方法或构造方法参数值,如果存在那么则直接使用该构造方法进行实例化
(2)如果没有确定的构造方法或构造方法参数值,那么
1)如果没有确定的构造方法,那么则找出类中所有的构造方法
2)如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化
3)如果有多个可用的构造方法或者当前Bean需要自动通过构造方法注入
4)根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数
5)对所有的构造方法进行排序,参数个数多的在前面
6)遍历每个构造方法
7)如果不是调用getBean方法时所指定的构造方法参数值,那么则根据构造方法参数类型找值
8)如果时调用getBean方法时所指定的构造方法参数值,就直接利用这些值
9)如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的
2.为什么分越少优先级越高?
(1)主要是计算找到的bean和构造方法参数类型匹配程度有多高。
(2)示例:假设bean的类型为A,A的父类是B,B的父类是C,同时A实现了接口D 如果构造方法的参数类型为A,那么完全匹配,得分为0 如果构造方法的参数类型为B,那么得分为2 如果构造方法的参数类型为C,那么得分为4 如果构造方法的参数类型为D,那么得分为
Object[] objects = new Object[]{new A()}; | |
// 0 | |
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{A.class}, objects)); | |
// 2 | |
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{B.class}, objects)); | |
// 4 | |
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{C.class}, objects)); | |
// 1 | |
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{D.class}, objects)); |
(3)所以,我们可以发现,越匹配分数越低
5)无参构造方法instantiateBean方法分析
//AbstractAutowireCapableBeanFactory类#instantiateBean方法 | |
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) { | |
try { | |
Object beanInstance; | |
if (System.getSecurityManager() != null) { | |
beanInstance = AccessController.doPrivileged( (PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this), getAccessControlContext()); | |
} | |
else { | |
//获取实例化策略并且进行实例化操作 | |
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); | |
} | |
// 包装成BeanWrapper | |
BeanWrapper bw = new BeanWrapperImpl(beanInstance); | |
initBeanWrapper(bw); | |
return bw; | |
} | |
catch (Throwable ex) { | |
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); | |
} | |
} | |
//SimpleInstantiationStrategy类#instantiate方法 | |
public Object instantiate(RootBeanDefinition bd, { String beanName, BeanFactory owner) | |
// bd对象定义中,是否包含MethodOverride列表,spring中有两个标签参数会产生MethodOverrides,分别是lookup-method,replaced-method | |
// 没有MethodOverrides对象,可以直接实例化 | |
if (!bd.hasMethodOverrides()) { | |
// 实例化对象的构造方法 | |
Constructor<?> constructorToUse; | |
// 锁定对象,使获得实例化构造方法线程安全 | |
synchronized (bd.constructorArgumentLock) { | |
// 查看bd对象里使用否含有构造方法 | |
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; | |
// 如果没有 | |
if (constructorToUse == null) { | |
// 从bd中获取beanClass | |
final Class<?> clazz = bd.getBeanClass(); | |
// 如果要实例化的beanDefinition是一个接口,则直接抛出异常 | |
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中的属性 | |
bd.resolvedConstructorOrFactoryMethod = constructorToUse; | |
} | |
catch (Throwable ex) { | |
throw new BeanInstantiationException(clazz, "No default constructor found", ex); | |
} | |
} | |
} | |
// 通过反射生成具体的实例化对象 | |
return BeanUtils.instantiateClass(constructorToUse); | |
} | |
else { | |
// 必须生成cglib子类 | |
return instantiateWithMethodInjection(bd, beanName, owner); | |
} | |
} | |
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | |
throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); | |
return getConstructor0(parameterTypes, Member.DECLARED); | |
} | |
private Constructor<T> getConstructor0(Class<?>[] parameterTypes, int which) throws NoSuchMethodException { | |
//获取所有的构造器 | |
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC)); | |
//遍历构造器,匹配的返回 | |
for (Constructor<T> constructor : constructors) { | |
if (arrayContentsEq(parameterTypes, | |
constructor.getParameterTypes())) { | |
return getReflectionFactory().copyConstructor(constructor); | |
} | |
} | |
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes)); | |
} | |
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new CircularRefA()); |