Spring源码问题:findAutowireCandidates这个if的意义是什么?

新手上路,请多包涵

这些天研究Spring源码,遇到一个问题始终想不明白,resolveDependency->doResolveDependency->findAutowireCandidates中有这样一段代码:

Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
    for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
            Class<?> autowiringType = classObjectEntry.getKey();
            // autowiringType是requiredType的父类或本身
            if (autowiringType.isAssignableFrom(requiredType)) {
                Object autowiringValue = classObjectEntry.getValue();
                autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
                if (requiredType.isInstance(autowiringValue)) {
                    result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
                    break;
                }
            }
        }

请问这个if (autowiringType.isAssignableFrom(requiredType))的意义是什么?
为此我做了个试验:
首先创建A、A1、A2,A1继承A,A2继承A1,其中没有任何代码。
然后创建User类,只有一个成员变量A1 a1:

public class User {
    @Autowired
    private A1 a1;
    public A1 getA1() {
        return a1;
    }
    public void setA1(A1 a1) {
        this.a1 = a1;
    }
}

findAutowireCandidates.xml:

 <bean class="A1" name="a1"/>
    <bean class="A2" name="a2"/>
    <bean class="findAutowireCandidates.User" name="user" autowire="byType"/>
    <context:component-scan base-package="findAutowireCandidates"/>

这种情况下一定会报异常,因为User类a1在自动注入的时候会有多个bean与之匹配,为了避免这种情况产生可以使用@Primary等方法,但那些不是要讨论的主题,这里用另一个方法,自定义一个BeanFactoryPostProcessor,向resolvableDependencies中注册一个A2:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        configurableListableBeanFactory.registerResolvableDependency(A2.class,new A2());
    }
}

最后写个main方法:

public class TestFindAutowireCandidates {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("findAutowireCandidates.xml");
    }
}

最后运行,会发现依然报错,原因依然是User的a1有多个bean与之匹配:a1、a2,接着对MyBeanFactoryPostProcessor做如下修改:

configurableListableBeanFactory.registerResolvableDependency(A.class,new A2());

把key改成A.class,再运行就不会报错了,而且User的a1注入的不是a1、a2,而是MyBeanFactoryPostProcessor中这个new出来的A2对象。

以上实验纠其原因,就是开头提到的这个if (autowiringType.isAssignableFrom(requiredType)),这个if的意思是如果autowiringType是requiredType的本身或其父类,才可以进来。

findAutowireCandidates这个方法的大概意思就是要找到与requiredType类型匹配的所有候选bean,先在resolvableDependencies中查找,再从容器中所有bean中查找。后者我没什么问题,主要是前者,为什么在resolvableDependencies中查找时,如果autowiringType是requiredType的子类会被筛选掉呢?也就是前面试验中第一种报错的情况:如果我在resolvableDependencies中注册A2.class,new A2()这个键值对,由于A2是A1的子类,这里就会被筛选掉,导致这个MyBeanFactoryPostProcessor写了跟没写一样;但如果你注册的是A.class,new A2()就会生效。

但是为啥会这么写呢?如果没有这个if (autowiringType.isAssignableFrom(requiredType))不是也OK么?直接判断if (requiredType.isInstance(autowiringValue))不就可以了?请明白的赐教!

阅读 2.6k
2 个回答

谈不上什么清除明白,只是在看见这个问题之后来兴趣了去翻了下源码,有兴趣可以讨论。

先说你第一种注入方式,我这里是通过了的。但它很明显不是从这个比较中获取的,是从上面的BeanFactoryUtils.beanNamesForTypeIncludingAncestors 中获取的两个候选者,在下面的foreach中,全部加入在后续方法determineAutowireCandidate 中决定,这里决定的因素是名称相同。

在说 registerResolvableDependency

/**
 * Register a special dependency type with corresponding autowired value.
 * <p>This is intended for factory/context references that are supposed
 * to be autowirable but are not defined as beans in the factory:
 * e.g. a dependency of type ApplicationContext resolved to the
 * ApplicationContext instance that the bean is living in.
 * <p>Note: There are no such default types registered in a plain BeanFactory,
 * not even for the BeanFactory interface itself.
 * @param dependencyType the dependency type to register. This will typically
 * be a base interface such as BeanFactory, with extensions of it resolved
 * as well if declared as an autowiring dependency (e.g. ListableBeanFactory),
 * as long as the given value actually implements the extended interface.
 * @param autowiredValue the corresponding autowired value. This may also be an
 * implementation of the {@link org.springframework.beans.factory.ObjectFactory}
 * interface, which allows for lazy resolution of the actual target value.
 */

并不是特别为@Autowired 准备的,从代码中也能看出 a1,a2,new A2 是全部加入了,在determineAutowireCandidate 中,谁最先符合条件,就返回谁,这里的haspMap是linkedHaspMap ,在resolvableDependencies 中?,名称相同? 而 registerResolvableDependency那个是最先加入的,且符合 resolvableDependencies.containsValue()所以返回了。

最后说,这条判断是很有必要的,如果要获取申明的依赖对象,则获取的key 应该是其父类或者自己,这很符合byType的逻辑。

这个resolvableDependencies可不会只有你注册的A1,人家前面做一个判断也挺正常的
多个key对应一个类型上,你要是不做判断的话,那就是选择到第一数据了
image.png
这个更直观
image.png

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题