一、收集注入元数据
在Spring依赖注入15-Spring源码-依赖注入(1)中讲了依赖注入的收集注解元数据。我们接着上文的查找元数据详细的展开说明一下:创建需要注入的元信息AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
// 用于判断某个类是否可能 被标记指定的某个注解(@Authowired).见代码片段1
// @Autowired、@Value 以及 @Inject
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
// 判断当前类或其字段或其方法是否标注了autowiredAnnotationTypes中的注解,没有的话直接返回空
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 遍历targetClass中的字段。见代码片段2
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 获取field上的@Autowired注解信息.见代码片段3
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// 如果字段是静态类型是不会进行注入的
if (Modifier.isStatic(field.getModifiers())) {
return;
}
// 获取@Autowired注解中的required属性
boolean required = determineRequiredStatus(ann);
// 将装成AutowiredFieldElement添加进currElements
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 遍历targetClass中的方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 找到桥接方法.见代码片段4
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
// 判断方法的可见性,如果不可见则直接返回
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// 获取method上的@Autowired注解信息
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);
}
}
// 获取@Autowired注解中的required属性
boolean required = determineRequiredStatus(ann);
// 将方法和目标类型封装成属性描述符
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// 封装成AutowiredMethodElement添加进currElements
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
// 将currElements整个添加进elements
elements.addAll(0, currElements);
// 获取targetClass的父类,进行下一次循环
targetClass = targetClass.getSuperclass();
}
// 当targetClass为空或者targetClass等于Object.class时会退出循环
while (targetClass != null && targetClass != Object.class);
// 将elements和clazz封装成InjectionMetadata返回
return InjectionMetadata.forElements(elements, clazz);
}
代码片段1,用于判断某个类是否可能 被标记指定的某个注解
// 用于判断某个类是否可能 被标记指定的某个注解
public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {
return isCandidateClass(clazz, annotationType.getName());
}
public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
// 如果注解所在包是java开头,任何类上都可能标记这个注解
// Java开头的注解包就是JDK自带的注解,任何类都可能标记.这个时候返回True就没什么问题
if (annotationName.startsWith("java.")) {
return true;
}
// 注解所在包不是java开头的情况
// 可以认为是自定义注解,例如Spring的@Service @Autowired @Value 对Spring来说就是其自定义注解
// 如果类的包是以java开头,则不可能标记自定义的注解
if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
return false;
}
return true;
}
// 这里的class就是自己的class类。如果类的包是以java开头,则不可能标记自定义的注解
// 如果类的包不是以java开头
static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {
return (type.getName().startsWith("java.") || type == Ordered.class);
}
代码片段2,遍历targetClass中的字段
public static void doWithLocalFields(Class<?> clazz, ReflectionUtils.FieldCallback fc) {
// 获取类上的所有的字段,包括共有的字段和自由的字段
Field[] var2 = getDeclaredFields(clazz);
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Field field = var2[var4];
try {
// 处理回调方法
fc.doWith(field);
} catch (IllegalAccessException var7) {
throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + var7);
}
}
}
代码片段3,获取field上的@Autowired注解信息
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
// 创建MergedAnnotations实例。该实例是定义了大量的关于注解的API操作
MergedAnnotations annotations = MergedAnnotations.from(ao);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
// 判断是否包含@Authorwied
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}
关于MergedAnnotations
的用法可以参考 17-spring源码-组合注解的处理。
代码片段4 找到桥接方法
public static Method findBridgedMethod(Method bridgeMethod) {
// 判断方法是否为桥接方法。参考 https://www.cnblogs.com/guangshan/p/4661305.html
// 桥接方法的进阶版本:https://cloud.tencent.com/developer/article/1656258
if (!bridgeMethod.isBridge()) {
return bridgeMethod;
} else {
// 继续的寻找bridgeMethod.DeclaringClass
Method bridgedMethod = (Method)cache.get(bridgeMethod);
if (bridgedMethod == null) {
List<Method> candidateMethods = new ArrayList();
MethodFilter filter = (candidateMethod) -> {
return isBridgedCandidateFor(candidateMethod, bridgeMethod);
};
// 递归该类及其所有父类上的所有方法,符合筛选条件就添加进来。
ReflectionUtils.doWithMethods(bridgeMethod.getDeclaringClass(), candidateMethods::add, filter);
if (!candidateMethods.isEmpty()) {
bridgedMethod = candidateMethods.size() == 1 ? (Method)candidateMethods.get(0) : searchCandidates(candidateMethods, bridgeMethod);
}
if (bridgedMethod == null) {
bridgedMethod = bridgeMethod;
}
cache.put(bridgeMethod, bridgedMethod);
}
return bridgedMethod;
}
}
桥接方法的进阶版本,从JVM的角度解释了桥接方法:
小结
收集注入元数据过程,首先调用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition
方法,然后调用findAutowiringMetadata
方法查找元数据,如果找到相应类的注入元数据 ,就会调用buildAutowiringMetadata
方法创建InjectionMetadata
,最后将新创建的注入元数据保存在injectionMetadataCache
缓存起来