spring中自动注入注解的实现方式

 更新时间:2024年09月19日 09:18:15   作者:潭影空人心  
在Spring框架中,AutowiredAnnotationBeanPostProcessor负责处理@Autowired和@Value注解,实现依赖注入,首先通过TypeMappedAnnotations获取注解,并根据注解属性构建InjectionMetadata,存入缓存

在前面的文章中,我们介绍过,基于注解的包扫描模式下,会默认注册一系列的后置处理器,其中,就包含一个 AutowiredAnnotationBeanPostProcessor,这个处理器默认就会处理 @Autowired@Value 注解。

类结构

从图中可知,这是一个 MergedBeanDefinitionPostProcessor 实现类,所以会在每一个实例对象创建时,当实例化结束,还未提前暴露时,对实例对象进行处理。

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

获取注解

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	// 确定缓存 key
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// 从缓存获取 InjectionMetadata
	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	// metadata 为 null,表示需要刷新
	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
				metadata = buildAutowiringMetadata(clazz);
				// 放入缓存
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
	return metadata;
}
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
	// autowiredAnnotationTypes 两种类型 @Autowired/@Value
	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<>();
		
		// 处理 Field 上注解
		ReflectionUtils.doWithLocalFields(targetClass, field -> {
			MergedAnnotation<?> ann = findAutowiredAnnotation(field);
			if (ann != null) {
				// static 不支持注入
				if (Modifier.isStatic(field.getModifiers())) {
					if (logger.isInfoEnabled()) {
						logger.info("Autowired annotation is not supported on static fields: " + field);
					}
					return;
				}
				// 默认 true
				boolean required = determineRequiredStatus(ann);
				currElements.add(new AutowiredFieldElement(field, required));
			}
		});

		// 处理 Method 上注解
		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);
                // Method 比 Field 多了 PropertyDescriptor
				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);
}

@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
	// TypeMappedAnnotations
	MergedAnnotations annotations = MergedAnnotations.from(ao);
	for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
		// 获取指定 type 对应的 TypeMappedAnnotation,存在,将对应的 TypeMappedAnnotation 返回
		MergedAnnotation<?> annotation = annotations.get(type);
		if (annotation.isPresent()) {
			return annotation;
		}
	}
	return null;
}

可以看到,获取当前类及其父类中 Field 或 Method 上定义的注解,此时封装为 TypeMappedAnnotations,接着获取指定注入注解类型对应的 TypeMappedAnnotation,存在,返回 TypeMappedAnnotation,从中获取注解属性 "required" 对应的值,默认 true,之后将 Field 或 Method 封装成 InjectionMetadata.InjectedElement,加入 elements 集合,最后包装成 InjectionMetadata,放入 AutowiredAnnotationBeanPostProcessor 中 injectionMetadataCache 缓存。

有一点要注意,就是 Method 注入时,虽然获取了 pd,但测试中 pd 为 null,也不影响注入,由此也说明注入的方法不一定必须是 setter 或 getter 方法。

注入

实例化完 bean 之后,进行属性填充,执行 AbstractAutowireCapableBeanFactory#populateBean,此时会调用 InstantiationAwareBeanPostProcessor#postProcessProperties,AutowiredAnnotationBeanPostProcessor 实现了这个方法。

@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 前面已经介绍过了,此时会直接从缓存获取到 InjectionMetadata。

// InjectionMetadata
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Collection<InjectedElement> checkedElements = this.checkedElements;
	Collection<InjectedElement> elementsToIterate =
			(checkedElements != null ? checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		for (InjectedElement element : elementsToIterate) {
			element.inject(target, beanName, pvs);
		}
	}
}

遍历,对每个 InjectedElement,调用 inject 方法。从上面介绍可知,InjectedElement 共两种,分别是针对 Field 的 AutowiredFieldElement,以及针对 Method 的 AutowiredMethodElement。下面分别介绍。

Field 注入

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Field field = (Field) this.member;
	Object value;
	// false
	if (this.cached) {
		try {
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Unexpected removal of target bean for cached argument -> re-resolve
			value = resolveFieldValue(field, bean, beanName);
		}
	}
	else {
		value = resolveFieldValue(field, bean, beanName);
	}
	if (value != null) {
        // 反射注入值
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
	DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
	desc.setContainingClass(bean.getClass());
	Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
	Assert.state(beanFactory != null, "No BeanFactory available");
	// 创建了一个 SimpleTypeConverter 作为 typeConverter
	TypeConverter typeConverter = beanFactory.getTypeConverter();
	Object value;
	try {
		// 解析依赖,对于基本类型,解析后经过转换返回包装类型
		value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
	}
	catch (BeansException ex) {
		throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
	}
	synchronized (this) {
		if (!this.cached) {
			Object cachedFieldValue = null;
			if (value != null || this.required) {
				cachedFieldValue = desc;
				registerDependentBeans(beanName, autowiredBeanNames);
				if (autowiredBeanNames.size() == 1) {
					String autowiredBeanName = autowiredBeanNames.iterator().next();
					if (beanFactory.containsBean(autowiredBeanName) &&
							beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
						cachedFieldValue = new ShortcutDependencyDescriptor(
								desc, autowiredBeanName, field.getType());
					}
				}
			}
			this.cachedFieldValue = cachedFieldValue;
			this.cached = true;
		}
	}
	return value;
}

逻辑比较简单,解析出注入的值,接着反射注入值。

Method 注入

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	if (checkPropertySkipping(pvs)) {
		return;
	}
	Method method = (Method) this.member;
	Object[] arguments;
	if (this.cached) {
		try {
			arguments = resolveCachedArguments(beanName);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Unexpected removal of target bean for cached argument -> re-resolve
			arguments = resolveMethodArguments(method, bean, beanName);
		}
	}
	else {
		// 解析参数
		arguments = resolveMethodArguments(method, bean, beanName);
	}
	if (arguments != null) {
		try {
			// 反射调用方法,注入属性
			ReflectionUtils.makeAccessible(method);
			method.invoke(bean, arguments);
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
	}
}
@Nullable
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
	int argumentCount = method.getParameterCount();
	Object[] arguments = new Object[argumentCount];
	DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
	Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
	Assert.state(beanFactory != null, "No BeanFactory available");
	TypeConverter typeConverter = beanFactory.getTypeConverter();
	// 解析每一个参数
	for (int i = 0; i < arguments.length; i++) {
		// 封装 MethodParameter
		MethodParameter methodParam = new MethodParameter(method, i);
		// 封装 DependencyDescriptor
		DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
		currDesc.setContainingClass(bean.getClass());
		descriptors[i] = currDesc;
		try {
			// 解析依赖,required 默认 true,遇见无法解析的直接抛出异常
			Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
			if (arg == null && !this.required) {
				arguments = null;
				break;
			}
			// 构造参数
			arguments[i] = arg;
		}
		catch (BeansException ex) {
			throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
		}
	}
	synchronized (this) {
		if (!this.cached) {
			if (arguments != null) {
				DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
				registerDependentBeans(beanName, autowiredBeans);
				if (autowiredBeans.size() == argumentCount) {
					Iterator<String> it = autowiredBeans.iterator();
					Class<?>[] paramTypes = method.getParameterTypes();
					for (int i = 0; i < paramTypes.length; i++) {
						String autowiredBeanName = it.next();
						if (beanFactory.containsBean(autowiredBeanName) &&
								beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
							cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
									descriptors[i], autowiredBeanName, paramTypes[i]);
						}
					}
				}
				this.cachedMethodArguments = cachedMethodArguments;
			}
			else {
				this.cachedMethodArguments = null;
			}
			this.cached = true;
		}
	}
	return arguments;
}

可以看到,不管是 Field 注入还是 Method 注入,都是先封装出一个 DependencyDescriptor,接着执行 beanFactory.resolveDependency 进行依赖的解析,不同点在于 Field 解析完就返回了,而 Method 解析完是为了构造出参数数组。

之后,不管是 Field 注入,还是 Method 注入,都是利用反射完成注入。这也说明,Method 注入时,只要能正常的封装出参数数组,就能完成属性或字段注入。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java中Stream流去除List重复元素的方法

    Java中Stream流去除List重复元素的方法

    这篇文章主要为大家详细介绍了Java中Stream流去除List重复元素的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 基于springboot 长轮询的实现操作

    基于springboot 长轮询的实现操作

    这篇文章主要介绍了基于springboot 长轮询的实现操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • SpringBoot手动开启事务:DataSourceTransactionManager问题

    SpringBoot手动开启事务:DataSourceTransactionManager问题

    这篇文章主要介绍了SpringBoot手动开启事务:DataSourceTransactionManager问题,具有很好的价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Java如何生成随机数不了解下吗

    Java如何生成随机数不了解下吗

    我们在学习 Java 基础时就知道可以生成随机数,可以为我们枯燥的学习增加那么一丢丢的乐趣,本文就来和大家介绍Java生成随机数的常用方法,需要的可以参考下
    2023-08-08
  • JavaCV实现人脸检测功能

    JavaCV实现人脸检测功能

    这篇文章主要为大家详细介绍了JavaCV实现人脸检测功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • Java Lambda表达式超详细介绍

    Java Lambda表达式超详细介绍

    这篇文章主要介绍了Java Lambda表达式,Lambda表达式是Java SE 8中一个重要的新特性, Lambda 表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭包(Closure),下面来看看文章具体的详细介绍吧
    2022-02-02
  • 23种设计模式(2) java工厂模式

    23种设计模式(2) java工厂模式

    这篇文章主要为大家详细介绍了23种设计模式之java工厂模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • Java中的SimpleDateFormat的线程安全问题详解

    Java中的SimpleDateFormat的线程安全问题详解

    这篇文章主要介绍了Java中的SimpleDateFormat的线程安全问题详解,sonar 是一个代码质量管理工具,SonarQube是一个用于代码质量管理的开放平台,为项目提供可视化报告, 连续追踪项目质量演化过程,需要的朋友可以参考下
    2024-01-01
  • 详解Springboot+React项目跨域访问问题

    详解Springboot+React项目跨域访问问题

    这篇文章主要介绍了详解Springboot+React项目跨域访问问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • Spring-Security实现登录接口流程

    Spring-Security实现登录接口流程

    Security 是 Spring 家族中的一个安全管理框架,SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器,这篇文章主要介绍了Spring-Security实现登录接口,需要的朋友可以参考下
    2023-05-05

最新评论