在Spring中,autowire注解的功能主要是通过AutowiredAnnotationBeanPostProcessor类来实现的,AutowiredAnnotationBeanPostProcessor类本身会通过xml标签"context:annotation-config" and "context:component-scan"进行注册,可以去掉或者管理默认的注解配置,如果你希望去声明一个个性化的AutowiredAnnotationBeanPostProcessor bean定义。注意:注解注入会在XML注入之前执行,后来的配置会覆盖前边所有途径的配置。下边是AutowiredAnnotationBeanPostProcessor的类图。
我们从最上边的类来分析下,首先是BeanPostProcessor类,这个类是bean工厂的hook,用于对新建的bean实例的个性化的改造,比如检查标记接口(类似Serializable)或者通过代理来包装bean。ApplicationContexts可以自动检测到自身bean定义中的BeanPostProcessor类,并应用到后续创建的bean。简单的bean工厂允许通过编程式的注册post-processor,可以对所有通过这个工厂创建的bean生效。特别的,Post-processors处理标记接口的bean通常会实现postProcessBeforeInitialization,而通过代理来包装bean的post-processors通常会实现postProcessAfterInitialization。
InstantiationAwareBeanPostProcessor接口继承了BeanPostProcessor接口,在BeanPostProcessor的基础之上添加了两个回调,一个是before-instantiation,另一个是after-instantiation,但在属性被赋值或者注入之前。通常被用于控制特定bean的默认实例化过程,比如用特殊的TargetSource创建(池化目标,懒初始化目标)代理,或者实现额外的诸如策略,如属性注入。
SmartInstantiationAwareBeanPostProcessor扩展了InstantiationAwareBeanPostProcessor接口,加了一个回调,用来推断被处理bean的实际类型。
InstantiationAwareBeanPostProcessorAdapter类实现了InstantiationAwareBeanPostProcessor接口,所有的方法都是一个空实现,不会改变容器实例化的bean的正常的处理。子类可以根据需要实现该类的某几个方法。
除了上边的这几个接口(类),上图中还有一个接口MergedBeanDefinitionPostProcessor,这个是运行时复合bean定义的回调接口。BeanPostProcessor的实现可以实现这个子接口来后处理 符合bean的定义(原始bean定义的处理过的副本),Spring用来创建一个新的bean实例。
接下来就是我们最主要的实现类AutowiredAnnotationBeanPostProcessor,它被用来注入带注解的属性,setter方法和任意的config方法。主要检测通过Java5中的注解来注入的类:@Autowired和@Value。注入的逻辑主要通过postProcessPropertyValues方法来实现,对于每一个新建的bean,都会调用该方法来进行注入。有两种注入方式:AutowiredMethodElement和AutowiredFieldElement,分别是方法注入和属性注入。
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
//查找需要进行注入的属性
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//从Spring容器中获取对应的bean或者value进行注入
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;
}
上边的方法逻辑很简单, 就是先查找需要注入的数据,然后调用
inject进行注入。
注解的原理最后竟然真的是反射,这句话听说了无数遍,直到今天见到了真容,哭。