老铁,天天码的@Autowired你知道怎么实现的吗?

简介: 该文章主要介绍了Spring框架中@Autowired注解的工作原理,包括@Autowired注解的用途、实现机制以及源码分析。

前言

Autowired注解是spring提供自动装配功能的注解,通过这个注解,spring能够在bean的依赖注入时注入相应的bean属性。 作为Java开发者,每天都可能用到Autowire注解,理解这个注解的实现流程是很有必要的,本文将介绍@Autowired的工作原理。

spring通过一个AutowiredAnnotationBeanPostProcessor后置处理器来实现@Autowired的功能,这个后置处理器即实现了MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法功能,又实现了InstantiationAwareBeanPostProcessorAdapter后置处理器的postProcessProperties方法和postProcessPropertyValues。

image.png

原理分析

下面我们先分析这两个后置处理的提供的功能。

一、Autowired注解元信息解析过程:MergedBeanDefinitionPostProcessor

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
   
   

/**

* 提供修改beandefinition的回调函数

* @see AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors

*/

void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

/**

* 重置回调,可用于清理资源

* @see DefaultListableBeanFactory#resetBeanDefinition

*/

default void resetBeanDefinition(String beanName) {
   
   

}

}

既然MergedBeanDefinitionPostProcessor有修改beandefinition的能力,那么看下AutowiredAnnotationBeanPostProcessor是怎么运用这个能力的。


public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter

implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
   
   

//需要处理的注解类型

private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);

//这里是注解和注解目标对应的对象类信息缓存,避免多次读取

private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);

/**

* 这里可以看出默认会处理@Autowired,@Value,@Inject注解

*/

@SuppressWarnings("unchecked")

public AutowiredAnnotationBeanPostProcessor() {
   
   

this.autowiredAnnotationTypes.add(Autowired.class);

this.autowiredAnnotationTypes.add(Value.class);

this.autowiredAnnotationTypes.add((Class<? extends Annotation>)

ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));

}

/**
* 实现MergedBeanDefinitionPostProcessor接口方法,提供修改beandefinition的能力
*/
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   
   

//查找当前bean类型里所有加了autowiredAnnotationTypes注解的属性元信息

InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);

//将这些元信息和beandefinition绑定

metadata.checkConfigMembers(beanDefinition);

}

@Override

public void resetBeanDefinition(String beanName) {
   
   

this.lookupMethodsChecked.remove(beanName);

this.injectionMetadataCache.remove(beanName);

}

}

findAutowiringMetadata方法就是查找bean类型里符合autowiredAnnotationTypes的元信息


//根据class信息查找属性或方法的自动装配元信息

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;

}

//根据class信息查找自动装配注解元信息和目标属性和方法信息

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
   
   

List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();

Class<?> targetClass = clazz;

do {
   
   

//查找符合自动装配的属性注解元信息(属性对象)

final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

ReflectionUtils.doWithLocalFields(targetClass, field -> {
   
   

AnnotationAttributes ann = findAutowiredAnnotation(field);

if (ann != null) {
   
   

if (Modifier.isStatic(field.getModifiers())) {
   
   

if (logger.isInfoEnabled()) {
   
   

logger.info("Autowired annotation is not supported on static fields: " + field);

}

return;

}

boolean required = determineRequiredStatus(ann);

currElements.add(new AutowiredFieldElement(field, required));

}

});

//查找符合自动装配的方法注解元信息(方法对象)

ReflectionUtils.doWithLocalMethods(targetClass, method -> {
   
   

Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);

if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
   
   

return;

}

AnnotationAttributes 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 new InjectionMetadata(clazz, elements);

}

上面的步骤通过解析得到了符合自动装配注解bean的属性对象和方法对象,并和bean的definition进行绑定。这就是AutowiredAnnotationBeanPostProcessor利用MergedBeanDefinitionPostProcessor扩展点实现的功能。

二、Autowired注解注入对象流程:InstantiationAwareBeanPostProcessorAdapter

上一步这里只是解析到了需要自动装配的属性,还没有注入相应对象。那么注入对象的过程由AutowiredAnnotationBeanPostProcessor实现了InstantiationAwareBeanPostProcessorAdapter的功能。


public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter

implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
   
   

//处理属性的功能,即完整自动注入属性
@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;

}

}
相关文章
|
3月前
|
数据处理
杨校老师课堂之封装工具类【防止重复提交拦截器|全局异常处理器|获取IP及地址】
杨校老师课堂之封装工具类【防止重复提交拦截器|全局异常处理器|获取IP及地址】
16 0
|
4月前
|
存储 缓存 监控
瑟瑟发抖的Redis夺命连环75问(六万多字答案和示例代码)
六万三千多字答案和示例代码,75道Redis题含盖Redis相关基础、高级和实践问题。Redis(Remote Dictionary Server,远程字典服务器)是一个开源的高性能键值对存储系统,通常被用作数据库、缓存或消息中间件。支持多种数据结构,如字符串(strings)、集合(sets)、有序集合(sorted sets)、哈希表(hashes)、列表(lists)等。1性能高、支持多种数据结构:、原子操作、持久性、主从复制、高可用与分区、发布/订阅和Lua 脚本待特性。
252 0
|
前端开发 Java API
java springboot 手把手带你敲微信公众号自定义登录实现token拦截【硬货教程】
java springboot 手把手带你敲微信公众号自定义登录实现token拦截【硬货教程】
|
缓存 算法 NoSQL
短链是什么原理?怎么实现呢?
内容营销中给用户推送营销消息最常见的方式就是发短信,比如三大运营商移动、联通、电信平时会发送一些诸如套餐办理、消费查询、话费充值这些短信,还有像银行、云服务厂商等等推送的各种包含查询服务的短信等等。
短链是什么原理?怎么实现呢?
|
Web App开发 JSON 前端开发
【低效编码】一个@ResponseBody注解没加让我这个菜鸟原形毕露
您好,我是码农飞哥,感谢您阅读本文!如果此文对您有所帮助,请毫不犹豫的一键三连吧。小伙伴们,有啥想看的,想问的,欢迎积极留言告诉我喔。 。
172 0
【低效编码】一个@ResponseBody注解没加让我这个菜鸟原形毕露
|
Java
java学习第九天笔记-字符串186-手机号屏蔽
java学习第九天笔记-字符串186-手机号屏蔽
59 0
java学习第九天笔记-字符串186-手机号屏蔽
|
Java
java学习第十二天笔记-字符串231-完整代码实现1注册
java学习第十二天笔记-字符串231-完整代码实现1注册
63 0
java学习第十二天笔记-字符串231-完整代码实现1注册
|
Java
java学习第十二天笔记-字符串228-注册逻辑
java学习第十二天笔记-字符串228-注册逻辑
46 0
java学习第十二天笔记-字符串228-注册逻辑
|
JavaScript Java
java实现图片验证码全套实现方式
java实现图片验证码全套实现方式
132 0
|
开发框架 Java 编译器
Java 注解说的明明白白,清清楚楚,记得点赞关注
注解是开发框架的必备技术,也算是Java中相对高级的技术,不知道为什么一直没有想起来写,今天写一下,让我们开始吧。
115 0
Java 注解说的明明白白,清清楚楚,记得点赞关注