spring 中自动注入注解的实现

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

类结构

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

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

获取注解

java 复制代码
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 实现了这个方法。

java 复制代码
@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。

java 复制代码
// 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 注入

java 复制代码
@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 注入

java 复制代码
@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 解析完是为了构造出参数数组。依赖的解析可参考 spring 注解模式下对依赖的解析

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

相关推荐
此乃大忽悠2 分钟前
身份认证缺陷
java·数据库·webgoat·身份认证缺陷
Honyee11 分钟前
java使用UCanAccess操作Access
java·后端
秋千码途12 分钟前
小架构step系列10:日志热更新
java·linux·微服务
她说人狗殊途15 分钟前
浅克隆 深克隆
java
timing99417 分钟前
SQLite3 中列(变量)的特殊属性
java·jvm·sqlite
八苦19 分钟前
留个VKProxy性能测试记录
后端
SimonKing23 分钟前
你的Redis分布式锁还在裸奔?看门狗机制让锁更安全!
java·后端·程序员
追逐时光者23 分钟前
一个 .NET 开源、免费、以社区为中心的单元测试框架
后端·.net
你喜欢喝可乐吗?1 小时前
RuoYi-Cloud 验证码处理流程
java·spring cloud·微服务·vue
Java技术小馆1 小时前
langChain开发你的第一个 Agent
java·面试·架构