推断构造方法源码解析
- 一、确认候选构造——AutowireAnnotationBeanPostProcessor#determineCandidateConstructors
- 二、autowireConstructor 方法源码解析
- 三、总结
阅读此需阅读下面这些博客先 |
---|
【Spring源码分析】Bean的元数据和一些Spring的工具 |
【Spring源码分析】BeanFactory系列接口解读 |
【Spring源码分析】执行流程之非懒加载单例Bean的实例化逻辑 |
【Spring源码分析】从源码角度去熟悉依赖注入(一) |
【Spring源码分析】从源码角度去熟悉依赖注入(二) |
【Spring源码分析】@Resource注入的源码解析 |
【Spring源码分析】循环依赖的底层源码剖析 |
Spring 在推断构造方法的逻辑上面写的实在太复杂了,构造种类贼多贼多,恕我实力有限,这里的话算不上源码分析,只能说是原理吧,这我只考虑了平常开发会遇到的,什么getBean去添加参数的、BeanDefinition去填充的我都一概跳过,看不懂一点(比如多参构造参数相同的情况下(@Autowired注解修饰后的required为false)会进行评分操作,有点复杂,感觉遇不着就不想研究了)。
(这篇博客可能有点水了)
一、确认候选构造——AutowireAnnotationBeanPostProcessor#determineCandidateConstructors
确认候选的构造也是通过 BeanPostProcessor 来进行的(SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
),引进的代码如下:
// Candidate constructors for autowiring?// 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中的哪些构造方法// 比如AutowiredAnnotationBeanPostProcessor会把加了@Autowired注解的构造方法找出来,具体看代码实现会更复杂一点Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);@Nullableprotected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)throws BeansException {if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);if (ctors != null) {return ctors;}}}return null;}
Spring 实现的 SmartInstantiationAwareBeanPostProcessor 的 determineCandidateConstructors 方法中就一个对其进行实现了——AutowireAnnotationBeanPostProcessor。
下面俺对其核心代码进行解析:
@Override@Nullablepublic Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)throws BeanCreationException {// Quick check on the concurrent map first, with minimal locking.Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);if (candidateConstructors == null) {// Fully synchronized resolution now...synchronized (this.candidateConstructorsCache) {candidateConstructors = this.candidateConstructorsCache.get(beanClass);if (candidateConstructors == null) {Constructor<?>[] rawCandidates;try {// 拿到所有的构造方法rawCandidates = beanClass.getDeclaredConstructors();} catch (Throwable ex) {throw new BeanCreationException(beanName,"Resolution of declared constructors on bean Class [" + beanClass.getName() +"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);}List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);// 用来记录required为true的构造方法,一个类中只能有一个required为true的构造方法Constructor<?> requiredConstructor = null;// 用来记录默认无参的构造方法Constructor<?> defaultConstructor = null;// 遍历每个构造方法for (Constructor<?> candidate : rawCandidates) {// 当前遍历的构造方法是否写了@AutowiredMergedAnnotation<?> ann = findAutowiredAnnotation(candidate);// 当前构造方法上加了@Autowiredif (ann != null) {// 整个类中如果有一个required为true的构造方法,那就不能有其他的加了@Autowired的构造方法// 若存在required为true的还存在其他的@Autowired注解就抛出异常if (requiredConstructor != null) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructor: " + candidate +". Found constructor with 'required' Autowired annotation already: " +requiredConstructor);}boolean required = determineRequiredStatus(ann);if (required) {if (!candidates.isEmpty()) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructors: " + candidates +". Found constructor with 'required' Autowired annotation: " +candidate);}// 记录唯一一个required为true的构造方法requiredConstructor = candidate;}// 记录所有加了@Autowired的构造方法,不管required是true还是false// 如果默认无参的构造方法上也加了@Autowired,那么也会加到candidates中candidates.add(candidate);// 从上面代码可以得到一个结论,在一个类中,要么只能有一个required为true的构造方法,要么只能有一个或多个required为false的方法} else if (candidate.getParameterCount() == 0) {// 记录唯一一个无参的构造方法defaultConstructor = candidate;}// 有可能存在有参、并且没有添加@Autowired的构造方法}if (!candidates.isEmpty()) {// Add default constructor to list of optional constructors, as fallback.// 如果不存在一个required为true的构造方法,则所有required为false的构造方法和无参构造方法都是合格的if (requiredConstructor == null) {if (defaultConstructor != null) {candidates.add(defaultConstructor);} else if (candidates.size() == 1 && logger.isInfoEnabled()) {logger.info("Inconsistent constructor declaration on bean with name '" + beanName +"': single autowire-marked constructor flagged as optional - " +"this constructor is effectively required since there is no " +"default constructor to fall back to: " + candidates.get(0));}}// 如果只存在一个required为true的构造方法,那就只有这一个是合格的candidateConstructors = candidates.toArray(new Constructor<?>[0]);}// 没有添加了@Autowired注解的构造方法,并且类中只有一个构造方法,并且是有参的else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {candidateConstructors = new Constructor<?>[]{rawCandidates[0]};}else {// 如果有多个有参、并且没有添加@Autowired的构造方法,是会返回空的candidateConstructors = new Constructor<?>[0];}this.candidateConstructorsCache.put(beanClass, candidateConstructors);}}}return (candidateConstructors.length > 0 ? candidateConstructors : null);}
就是说只有三种情况有可用的构造(这里是指会有返回的候选构造方法):
- 使用了 @Autowired 注解,有且只有一个 required 为 true;
- 使用了 @Autowired 注解,required 都为 false;
- 没有使用 @Autowired 注解,有且只有一个多参构造。
通过这些代码的解析可以知道:
- 含有多个参数多个构造和只有一个无参的都会走
instantiateBean
的逻辑,去通过无参构造去实例化,如果没有的话就抛异常咯,换句话说就是没用@Autowired注解就是去找无参,没有就抛异常。 - 有且只有一个 @Autowired 注解且required为true,有多个 @Autowired 注解,但是 required 都为 false,那么就是通过
autowireConstructor
方法去实现 Spring 的自动构造。
二、autowireConstructor 方法源码解析
太难了,看不了一点,直接阐述源码流程(和上面的接着的)。
上面确认候选构造的时候还有三种情况我们需要考虑:
- 使用了 @Autowired 注解,有且只有一个 required 为 true;
- 使用了 @Autowired 注解,required 都为 false;
- 没有使用 @Autowired 注解,有且只有一个多参构造。
也就是上面这三种情况会进入到 autowireConstructor
方法。
下面阐述一下流程:
- 首先是对构造进行个排序,以参数的个数降序排序,就是参数个数多的在前面:
- 然后去调用
beanFactory#resolveDependency
方法去给参数进行填充参数; - 如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的
也就是说构造方法要满足可用的话,必须所有的参数都是Spring容器中拥有的,可以注入的。
三、总结
本篇并不是Spring所有推断构造方法的逻辑,只是其中的一部分——AutowireAnnotationBeanPostProcessor#determineCandidateConstructors
中推断出来的构造方法是怎么处理的。
主要就是有无 @Autowired 注解俩各方面。
当有多个构造 @Autowired 注解,但是 required 都为 false 的话,考虑 autowireConstructor 的逻辑。先是将所候选的构造参数个数降序排序,然后逐个去匹配,看看参数是否都能在容器中找到,找不到就换下一个,找到就用该构造。