一、收集注入元数据
在Spring依赖注入15-Spring源码-依赖注入(1)中讲了依赖注入的收集注解元数据。我们接着上文的查找元数据详细的展开说明一下:创建需要注入的元信息AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {// 用于判断某个类是否可能 被标记指定的某个注解(@Authowired).见代码片段1// @Autowired、@Value 以及 @Injectif (!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中的字段。见代码片段2ReflectionUtils.doWithLocalFields(targetClass, field -> {// 获取field上的@Autowired注解信息.见代码片段3MergedAnnotation<?> ann = findAutowiredAnnotation(field);if (ann != null) {// 如果字段是静态类型是不会进行注入的if (Modifier.isStatic(field.getModifiers())) {return;}// 获取@Autowired注解中的required属性boolean required = determineRequiredStatus(ann);// 将装成AutowiredFieldElement添加进currElementscurrElements.add(new AutowiredFieldElement(field, required));}});// 遍历targetClass中的方法ReflectionUtils.doWithLocalMethods(targetClass, method -> {// 找到桥接方法.见代码片段4Method 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添加进currElementscurrElements.add(new AutowiredMethodElement(method, required, pd));}});// 将currElements整个添加进elementselements.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注解信息
@Nullableprivate MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {// 创建MergedAnnotations实例。该实例是定义了大量的关于注解的API操作MergedAnnotations annotations = MergedAnnotations.from(ao);for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {MergedAnnotation<?> annotation = annotations.get(type);// 判断是否包含@Authorwiedif (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/1656258if (!bridgeMethod.isBridge()) {return bridgeMethod;} else {// 继续的寻找bridgeMethod.DeclaringClassMethod 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缓存起来
