栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring注入点的扫描(Autowired)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring注入点的扫描(Autowired)

一、bean实例化后会调用postProcessMergedBeanDefinition后置处理器寻找注入点AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
        InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);
        metadata.checkConfigMembers(beanDefinition);
    }

二、findAutowiringMetadata先去缓存中看是否能获取到

    private InjectionMetadata findAutowiringMetadata(String beanName, Class clazz, @Nullable PropertyValues pvs) {
        String cacheKey = StringUtils.hasLength(beanName) ? beanName : clazz.getName();
        InjectionMetadata metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized(this.injectionMetadataCache) {
                metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
					//第一次缓存中肯定是没数据的
                    metadata = this.buildAutowiringMetadata(clazz);
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }

        return metadata;
    }

三、寻找注入点buildAutowiringMetadata(Class clazz)

private InjectionMetadata buildAutowiringMetadata(Class clazz) {
		
		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List elements = new ArrayList<>();
		Class targetClass = clazz;

		do {
			final List currElements = new ArrayList<>();
			//遍历所有属性
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				//查看属性上是否有@Autowired、@Value  @Inject注解
				MergedAnnotation ann = findAutowiredAnnotation(field);
				if (ann != null) {
					//静态属性不是注入点直接返回,@Resource中静态属性会报错(CommonAnnotationBeanPostProcessor处理@Resource)
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					//设置required值
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});
			//遍历所有方法
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				//此刻筛选掉桥接方法(父类泛型相关)子类继承父类的方法加上@Autowired注解,此刻子类会有两个方法,一个是父类桥接、一个自己实现的,过滤掉桥接方法
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				查看方法上是否有@Autowired、@Value  @Inject注解
				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);
					//把是Setget相关方法属性描述返回(我们在修改beandefinition中为属性赋值,这里优先级会高)
					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);
	}

匹配属性、方法是否匹配

private MergedAnnotation findAutowiredAnnotation(AccessibleObject ao) {
		MergedAnnotations annotations = MergedAnnotations.from(ao);
		for (Class type : this.autowiredAnnotationTypes) {
			MergedAnnotation annotation = annotations.get(type);
			if (annotation.isPresent()) {
				return annotation;
			}
		}
		return null;
	}
	//创建AutowiredAnnotationBeanPostProcessor时autowiredAnnotationTypes添加要扫描的注解
public AutowiredAnnotationBeanPostProcessor() {
		this.autowiredAnnotationTypes.add(Autowired.class);
		this.autowiredAnnotationTypes.add(Value.class);

		try {
			this.autowiredAnnotationTypes.add((Class)
					ClassUtils.forName("jakarta.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
			logger.trace("'jakarta.inject.Inject' annotation found and supported for autowiring");
		}
		catch (ClassNotFoundException ex) {
			// jakarta.inject API not available - simply skip.
		}

		try {
			this.autowiredAnnotationTypes.add((Class)
					ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
			logger.trace("'javax.inject.Inject' annotation found and supported for autowiring");
		}
		catch (ClassNotFoundException ex) {
			// javax.inject API not available - simply skip.
		

四、桥接方法的筛选demo

public interface UserInterface {
void setOrderService(T t);
}

@Component
public class UserService implements UserInterface {
private OrderService orderService;
@Override
@Autowired
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void test() {
System.out.println("test123");
}
}

UserService对应的字节码为会存在以下两个方法:
可以看到在UserSerivce的字节码中有两个setOrderService方法:

  1. public setOrderService(Lcom/zhouyu/service/OrderService;)V
  2. public synthetic bridge setOrderService(Ljava/lang/Object;)V
    并且都是存在@Autowired注解的。
    所以在Spring中需要处理这种情况,当遍历到桥接方法时,得找到原方法。

五、总结
1. 遍历当前类的所有的属性字段Field
2. 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该字段
是一个注入点
3. 如果字段是static的,则不进行注入
4. 获取@Autowired中的required属性的值
5. 将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到
currElements集合中。
6. 遍历当前类的所有方法Method
7. 判断当前Method是否是桥接方法,如果是找到原方法
8. 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法
是一个注入点
9. 如果方法是static的,则不进行注入
10. 获取@Autowired中的required属性的值
11. 将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到
currElements集合中。
12. 遍历完当前类的字段和方法后,将遍历父类的,直到没有父类。
13. 最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合
对象,并缓存。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/991906.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号