2023-09-16  阅读(44)
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/105139065

AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition

上一篇说了CommonAnnotationBeanPostProcessor的处理,处理完了就要轮到AutowiredAnnotationBeanPostProcessor的处理啦,我们来看看吧。
其实也就是去找AutowiredValue注解的方法和属性。

    	@Override
    	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    		InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    		metadata.checkConfigMembers(beanDefinition);
    	}

findAutowiringMetadata寻找自动装配元数据

和前面的CommonAnnotationBeanPostProcessorfindLifecycleMetadata很像吧,先找缓存,没有再创建,都用同步双重检测。

    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.
    		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    		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构建自动装配元数据

会去寻找有AutowiredValue注解的属性和方法,也包括自定义的父类的,封装成AutowiredMethodElement放入集合里。

    private InjectionMetadata buildAutowiringMetadata(final 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<>();
    
    			ReflectionUtils.doWithLocalFields(targetClass, field -> {
    				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
    				if (ann != null) {
    					if (Modifier.isStatic(field.getModifiers())) {//Autowired注解不支持静态方法
    						if (logger.isInfoEnabled()) {
    							logger.info("Autowired annotation is not supported on static fields: " + field);
    						}
    						return;
    					}
    					boolean required = determineRequiredStatus(ann);//查看是否是required的
    					currElements.add(new AutowiredFieldElement(field, required));
    				}
    			});
    			//处理桥接方法
    			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();
    		}
    		while (targetClass != null && targetClass != Object.class);
    
    		return InjectionMetadata.forElements(elements, clazz);
    	}

ReflectionUtils的doWithLocalFields处理属性

处理所有属性。

    public static void doWithLocalFields(Class<?> clazz, FieldCallback fc) {
    		for (Field field : getDeclaredFields(clazz)) {
    			try {
    				fc.doWith(field);
    			}
    			catch (IllegalAccessException ex) {
    				throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
    			}
    		}
    	}

ReflectionUtils的doWithLocalMethods处理方法

这个跟上个类型,就是处理方法的,处理方法上AutowiredValue注解。

    public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
    		Method[] methods = getDeclaredMethods(clazz, false);
    		for (Method method : methods) {
    			try {
    				mc.doWith(method);
    			}
    			catch (IllegalAccessException ex) {
    				throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
    			}
    		}
    	}

FieldCallback的doWith

其实就是个lambda表达式来处理,找出自动装配的注解,如果存在且非静态的就取出required,然后封装成AutowiredFieldElement加入集合。

    	field -> {
    				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
    				if (ann != null) {
    					if (Modifier.isStatic(field.getModifiers())) {//Autowired注解不支持静态方法
    						if (logger.isInfoEnabled()) {
    							logger.info("Autowired annotation is not supported on static fields: " + field);
    						}
    						return;
    					}
    					boolean required = determineRequiredStatus(ann);//查看是否是required的
    					currElements.add(new AutowiredFieldElement(field, required));
    				}

findAutowiredAnnotation

其实就是查看是否有AutowiredValue注解,有的话就返回。

    	@Nullable
    	private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
    		MergedAnnotations annotations = MergedAnnotations.from(ao);
    		for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
    			MergedAnnotation<?> annotation = annotations.get(type);
    			if (annotation.isPresent()) {
    				return annotation;
    			}
    		}
    		return null;
    	}

InjectionMetadata的forElements

最后会根据是否有属性和方法有AutowiredValue注解,没有就返回InjectionMetadata.EMPTY,有的话就封装成InjectionMetadata返回。

    	public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {
    		return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements));
    	}

InjectionMetadata的checkConfigMembers

如果集合里有注解的属性和方法,就会讲他们注册到beanDefinition的集合externallyManagedConfigMembers中。

    	public void checkConfigMembers(RootBeanDefinition beanDefinition) {
    		Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
    		for (InjectedElement element : this.injectedElements) {
    			Member member = element.getMember();
    			if (!beanDefinition.isExternallyManagedConfigMember(member)) {
    				beanDefinition.registerExternallyManagedConfigMember(member);
    				checkedElements.add(element);
    				if (logger.isTraceEnabled()) {
    					logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
    				}
    			}
    		}
    		this.checkedElements = checkedElements;
    	}

ApplicationListenerDetector的postProcessMergedBeanDefinition

这个只是记录下名字和是否是单例的映射。

    	@Override
    	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    		this.singletonNames.put(beanName, beanDefinition.isSingleton());
    	}

总结

其实applyMergedBeanDefinitionPostProcessors主要做的事就是用处理器把属性和方法上的自动装配的信息记录下来,放到bean定义里,后面进行填充的时候可以用到,其中就包括CommonAnnotationBeanPostProcessor的生命周期方法和webService,ejb,Resource注解信息以及AutowiredAnnotationBeanPostProcessorAutowiredValue注解信息。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文