refresh过程步骤太多了,今天基于常见的@Resource和@Autowired注解,阅读源码,分析异同。
环境 jdk1.8 、 spring-? 5.1.3 基于AnnotationConfigApplicationContext的Class数组构造:
public AnnotationConfigApplicationContext(Class>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
方法抽象入口在 AbstractAutowireCapableBeanFactory类的ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName),(详细路径在 refresh() -> finishBeanFactoryInitialization()->...后面自己找,写不下了)
方法实现:
CommonAnnotationBeanPostProcessor类(处理resource注解)的实现为 :
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//寻找@Resource下的元数据
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//具体注入方法
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
AutowiredAnnotationBeanPostProcessor类(处理autowired注解)的实现为 :
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//寻找@Autowired下的元数据
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//具体注入方法
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
InjectionMetadata 类 inject()方法的实现:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//checkedElements 就是检查到的 @Resource或者@Autowired下的属性或者方法(众所周知,@Resource和@Autowired都可以加载字段或者方法上)
Collection checkedElements = this.checkedElements;
Collection elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
//如果不为空,就执行相应的InjectedElement类(子类)的inject()方法
element.inject(target, beanName, pvs);
}
}
}
对于Resource注解 element.inject() 的实现类就是InjectedElement(属性(field)和方法(method)都在一个inject()方法里)
对于Autowired注解 属性在 AutowiredFieldElement中实现 , 方法在AutowiredMethodElement中实现。
对于Resource注解,如果没有指定name,判断字段名存在于beanFactory中,再以字段名为bean名称 执行上面的方法, 否则就执行下面的
对于Autowired注解执行此方法:
其实就是相同的方法。
如果没有其他条件限制,最后会到下面的方法中:
可以看到上面方法的具体逻辑是,根据需要注入的Class的Type寻找到此Type的所有bean的名称。
下面的方法:
:! isSelfReference 排除当前类的bean名称
:isAutowireCandidate ,核心实现:检查预选,从bean名称数组中挑选出@Qualifier的value的bean名称
具体实现就是拿到@Qualifier的value进行判断,过滤掉非value的bean名称,这也是为什么@Autowired 可以和@Qualifier(value = "??")联合使用,起到确定唯一bean的作用。
然后回到doResolveDependency()方法中。
对于required 为true的属性或者方法,bean为空就抛NoSuchBeanDefinitionException异常,如果bean数量大于一,会在determineAutowireCandidate()方法中进行primary,priority,以及通过字段名匹配bean名称 等操作再次判断,还是确定不了就抛NoUniqueBeanDefinitionException异常。
对 Resource:是在 autowireResource()方法中对字段名是否存在于beanFactory中作了判断,存在就以字段名为bean名称寻找唯一bean
对 Autowired:详情请看源码中的 DefaultListableBeanFactory类的doResolveDependency()方法中的determineAutowireCandidate()方法。 如果匹配到的bean数量大于一,则有一个与字段名判断的过程,选择和字段名相同的bean