一、Autowired注解的原理的概览
我们都知道一个Bean的大致生命周期有这几个阶段,实例化--> 属性填充 --> 初始化 --> 销毁回调
其中Autowired作用的时间就是在属性填充阶段,而且是通过AutowiredAnnotation BeanPostProcessor类进行处理的。注入的整体流程如下:
二、一步步分析Autowired的源码
AutowiredAnnotationBeanPostProcessor的postProcessProperties方法是我们此次分析的入口。其代码如下:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
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;
}
除了异常处理外,这里主要调用两个方法findAutowiringMetadata(用来查找标注有autowried注解的字段和方法)、metadata.inject(基于已经找到需要注入的信息来去spring容器中获取到对应的bean进行注入)。下面将重点分析这两个方法
1、findAutowiringMetadata方法详解
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
// 首先从缓存中获取当前需要进行注入的元数据,缓存的key为bean的名称(如果有),否则为类名
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// 判断是否刷新的条件是:1、metadata为null , 2、要注入的目标类跟当前入参中的clazz不是同一个类型
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
// 这里使用双重检查机制保证没有二次去出发构建自动注入的方法
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
// 构建需要自动的元数据类
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
上面的方法中我们优先从缓存中去获取自动注入的对象,如果缓存中有说明之前已经创建过了,直接进行返回,没有的化执行创建动作。接下来我们重点关注buildAutowiringMetadata方法
1.1 buildAutowiringMetadata方法解析
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 1、查找所有的标注了@Autowired的字段,生成AutowiredFieldElement对象,添加到currElements集合
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 2、查找所有的标注了@Autowired的方法,生成AAutowiredMethodElement对象,添加到currElements集合
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
// 3、向上递归父类,知道找到Object为止
while (targetClass != null && targetClass != Object.class);
// 4、 基于之前创建的AutowiredElements生成InjectionMetadata实例
return InjectionMetadata.forElements(elements, clazz);
}
该方法中主要做了三件事,
1、查找所有的标注了@Autowired的字段,生成AutowiredFieldElement对象,添加到currElements集合
2、查找所有的标注了@Autowired的方法,生成AAutowiredMethodElement对象,添加到currElements集合
3、 基于前两步创建的AutowiredElements生成InjectionMetadata实例
至此我们已经生成了InjectionMetadata对象,