点击关注公众号,实用技术文章及时了解

来源:blog.csdn.net/u013202238/article/details/107879726

本文主要基于SpringBoot-2.3.3.RELEASE, Spring-5.2.8.RELEASE 讲解.

Spring中@Autowire,@Value 注解实现原理,将这两个注解放到一块讲解主要是他们的实现基本一致。

本文涉及注解:@Autowire、@Value、@Qualifier、@Lazy、@Primary、@javax.annotation.Priority

相关类介绍

如下是几个重要的相关类:

  • org.springframework.beans.factory.config.BeanPostProcessor

  • org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor

  • org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

  • org.s.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

  • org.s.beans.factory.annotation.InjectionMetadata.InjectedElement

  • org.s.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement

  • org.s.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement

BeanPostProcessor

BeanPostProcessor是一个接口类,所有的bean在初始时期都会经过这个后置处理器,主要提供如下两个接口方法,

public interface BeanPostProcessor {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}

1、postProcessBeforeInitialization方法在bean初始化方法之前执行.例如bean实现了InitializingBean接口,会在InitializingBean#afterPropertiesSet方法之前执行。(不完全是这样,因为要看创建bean时,某个BeanPostProcessor实现类是否已经注册)

对于BeanPostProcessor#postProcessBeforeInitialization是否在@PostConstruct注解的初始化方法之前执行,这是不确定的,因为@PostConstruct初始化方法的执行是通过InitDestroyAnnotationBeanPostProcessor实现,并且InitDestroyAnnotationBeanPostProcessor通过重写BeanPostProcessor#postProcessBeforeInitialization实现@PostConstruct功能,CommonAnnotationBeanPostProcessor通过继承InitDestroyAnnotationBeanPostProcessor拥有了相同的能力,因此要看BeanPostProcessor 实现类被注册的顺序才能决定是否优先于@PostConstruct注解的方式执行。

2、postProcessAfterInitialization 方法在bean的初始化方法之后执行。

3、BeanPostProcessor 的子类接口如下UML图

4、AbstractAutowireCapableBeanFactory#initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd)源码如下:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {//判断是否实现了Aware接口,执行子类接口方法,//此时只有:BeanNameAware,BeanClassLoaderAware,BeanFactoryAwareinvokeAwareMethods(beanName, bean); }Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//调用BeanPostProcessor#postProcessBeforeInitialization//ApplicationContextAwareProcessor#postProcessBeforeInitialization//实现EnvironmentAware,..ApplicationContextAware等Aware的回调.wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//如果bean实现了InitializingBean接口则执行接口的afterPropertiesSet方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}

MergedBeanDefinitionPostProcessor

@Autowire,@Value 的查找 就是AutowiredAnnotationBeanPostProcessor通过重写该方法实现

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);default void resetBeanDefinition(String beanName) {}
}

BeanDefinition主要封装了bean的类信息,例如是否是单实例(Singleton),初始化方法名,依赖的bean名称等等。

在bean对象被创建之前,如果一个bean的BeanDefinition是一个子类,会先合并父类BeanDefinition,最终返回一个合并后的RootBeanDefinition,MergedBeanDefinitionPostProcessor则是Spring提供给开发的接口,便于对合并后的RootBeanDefinition做自定义修改。在调用AbstractAutowireCapableBeanFactory#doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)时回调MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法。扩展:40 个 SpringBoot 常用注解

InstantiationAwareBeanPostProcessor

看注释

@Autowire,@Value 的赋值 就是AutowiredAnnotationBeanPostProcessor通过重写postProcessProperties方法实现

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {//创建bean对象实例之前执行default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {return null;}//创建bean对象实例之后执行default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {return true;}//用于给bean对象中的成员属性赋值//@Autowire,@Value的赋值就是AutowiredAnnotationBeanPostProcessor通过重写该方法实现default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)throws BeansException {return null;}@Deprecated   //标记为过时default PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {return pvs;}
}

AutowiredAnnotationBeanPostProcessor

@Autowire,@Value,@Lookup等注解功能都是由AutowiredAnnotationBeanPostProcessor实现,在本文主要讲解@Autowire,@Value注解功能实现原理。

AutowiredAnnotationBeanPostProcessor的继承关系如下:

AutowiredAnnotationBeanPostProcessor的构造方法如下:主要定义了@Autowire,@Value两个注解是过滤目标bean的条件,如果bean中的Field、Method被标记这两个注解,则需要为其注入对应的bean或者属性值。

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

在实现@Autowire,@Value功能的过程中,AutowiredAnnotationBeanPostProcessor主要起到两个作用。

1、重写MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法,反射遍历beanClass中的所有Field和Method,查找bean中标记有@Autowire,@Value的Field、Method,封装到org.springframework.beans.factory.annotation.InjectionMetadata中。

保存在成员变量private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);中。

AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition 源码:

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

findAutowiringMetadata方法内部会调用到AnnotationUtils#isCandidateClass(Class<?>, Class<? extends Annotation>)用于判断某个类是否可能 被标记指定的某个注解。源码如下:

public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {return isCandidateClass(clazz, annotationType.getName());
}public static boolean isCandidateClass(Class<?> clazz, String annotationName) {//如果注解所在包是java开头,任何类上都可能标记这个注解if (annotationName.startsWith("java.")) {return true;}//注解所在包不是java开头的情况//可以认为是自定义注解,例如Spring的@Service @Autowired @Value 对Spring来说就是其自定义注解//如果类的包是以java开头,则不可能标记自定义的注解if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {return false;}return true;
}

AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)

static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {return (type.getName().startsWith("java.") || type == Ordered.class);
}

2、重写InstantiationAwareBeanPostProcessor#postProcessProperties方法,遍历injectionMetadataCache中的InjectionMetadata,调用org.springframework.beans.factory.annotation.InjectionMetadata#inject方法,为bean的@Autowire和@value属性字段赋值。

AutowiredAnnotationBeanPostProcessor#postProcessProperties 源码:

@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;
}

InjectionMetadata里面有个abstract内部类InjectionMetadata.InjectedElement,主要用于给Field或者Method赋值。

AutowiredAnnotationBeanPostProcessor中有两个私有内部类分别继承了InjectedElement。

  • AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: 通过反射给Field赋值.

  • AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement: 通过反射调用setter Method赋值.

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject源码:

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;if (this.cached) {try {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}catch (NoSuchBeanDefinitionException ex) {// Unexpected removal of target bean for cached argument -> re-resolvevalue = resolveFieldValue(field, bean, beanName);}}else {value = resolveFieldValue(field, bean, beanName);}if (value != null) {//反射赋值ReflectionUtils.makeAccessible(field);field.set(bean, value);}
}

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue源码:

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");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;
}

方法内部调用的beanFactory.resolveDependency(默认DefaultListableBeanFactory)整体逻辑大概如下:

1.判断Filed或者Method上是否有@Lazy注解,如果存在则创建代理,实现懒加载。

2.不是懒加载,则判断是否存在@Value注解,如果存在则获取value值,最后通过PropertySourcesPropertyResolver#getProperty(java.lang.String, java.lang.Class<T>, boolean)解析属性值(其实就是ConfigurableEnvironment中封装的MutablePropertySources集合),获取到属性值之后还会通过SpringEL进行一次解析。解析之后再由SimpleTypeConverter对象进行一次数据类型转换,转为Filed所需要的类型返回.

3.如果不存在@Value注解,则是根据@Autowire注入bean, 从DefaultListableBeanFactory中变量所有的beanName,判断对象类型是否和所需的相同,相同则保存beanName到List集合中(一个相同的接口可能出现多个实现类,所以用集合),

  • 遍历beanNames,判断每个bean是否符合要求,如果存在@Qualifier会判断名称是否匹配,匹配则获取对应bean对象。如果没有@Qualifier注解,则获取全部的bean对象,封装到Map中。

  • 如果Map中存在多个实例对象,再判断查找带有@Primary注解的实现类,返回对象。同类型实现@Primary只能有一个

  • 如果Map中存在多个实例对象,但是没有@Primary注解,再比较是否有@javax.annotation.Priority注解,选择优先高的返回,值越小优先级越高。

  • 根据名称匹配

  • 不符合以上规则,则抛出异常信息,出现多个bean实现。

Spring中依赖注入Bean的匹配逻辑如下

DefaultListableBeanFactory#determineAutowireCandidate

protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {Class<?> requiredType = descriptor.getDependencyType();String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);if (primaryCandidate != null) {return primaryCandidate;}String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);if (priorityCandidate != null) {return priorityCandidate;}// Fallbackfor (Map.Entry<String, Object> entry : candidates.entrySet()) {String candidateName = entry.getKey();Object beanInstance = entry.getValue();if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||matchesBeanName(candidateName, descriptor.getDependencyName())) {return candidateName;}}return null;
}

推荐

主流Java进阶技术(学习资料分享)

Java面试题宝典

加入Spring技术开发社区

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!

详解Spring中@Autowire,@Value 注解实现原理相关推荐

  1. java中config是什么意思,详解Spring中的JavaConfig注解

    前言 大家都知道传统spring一般都是基于xml配置的,不过后来新增了许多JavaConfig的注解.特别是springboot,基本都是清一色的java config,不了解一下,还真是不适应.这 ...

  2. 五篇教你掌握spring之三:详解Spring的bean以及注解开发

    详解Spring的bean以及注解开发 各种复杂类型的依赖注入 我们采用一个类的大杂烩的形式,新建一个Student package com.lwh.pojo;import java.util.*;p ...

  3. 用IDEA详解Spring中的IoC和DI(挺透彻的,点进来看看吧)

    用IDEA详解Spring中的IoC和DI 一.Spring IoC的基本概念 控制反转(IoC)是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心. 依赖注入(DI) ...

  4. 218.94.78.76:20001/index.php,详解spring中使用Elasticsearch的实例教程

    本篇文章主要介绍了详解spring中使用Elasticsearch的代码实现,具有一定的参考价值,有兴趣的可以了解一下 在使用Elasticsearch之前,先给大家聊一点干货. 1. ES和solr ...

  5. mysql 事物的持久性是指_详解MySQL中事务的持久性实现原理

    前言 说到数据库事务,大家脑子里一定很容易蹦出一堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等,但是可能很少有人真正的清楚事务的这些特性又是怎么实现的,为什 ...

  6. 详解Dart中如何通过注解生成代码

    简介:详解dart与java注解生成代码异同点 作者:闲鱼技术-龙湫 1.背景 最近在项目中使用到了Dart中的注解代码生成技术,这跟之前Java中APT+JavaPoet生成代码那套技术还是有一些不 ...

  7. 详解AQS中的condition源码原理

    摘要:condition用于显式的等待通知,等待过程可以挂起并释放锁,唤醒后重新拿到锁. 本文分享自华为云社区<AQS中的condition源码原理详细分析>,作者:breakDawn. ...

  8. 详解Spring中Bean的自动装配~

    目录 1. 环境搭建 2. byName.byType 3. 使用注解实现自动装配 @Autowired @Resource 小结 自动装配是Spring满足bean依赖的一种方式 Spring会在上 ...

  9. 详解Spring中的CharacterEncodingFilter--forceEncoding为true在java代码中设置失效--html设置编码无效...

    在项目中有很多让人头疼的问题,其中,编码问题位列其一,那么在Spring框架中是如何解决从页面传来的字符串的编码问题的呢?下面我们来看看Spring框架给我们提供过滤器CharacterEncodin ...

最新文章

  1. 对Squid使用的一些总结
  2. 面试官:听说你精通并发编程,来说说你对ThreadLocal的理解
  3. 第三章 改进神经网络的学习方式(上中)
  4. 杂项-权限管理:RBAC
  5. iview的表格自定义_Vue中使用iview-UI表格样式修改和使用自定义模板数据渲染相关...
  6. 【opencv学习笔记八】创建TrackBar轨迹条
  7. Taglist:Exuberant ctags.......
  8. Matlab如何实现建立ROS节点并进行实时通讯
  9. DataOutputStream 类 和DatainputStream类 的主要方法简单介绍,及代码演示。
  10. urllib,url中链接包含汉字怎么用百分号(%)加密处理
  11. ThreadLocal学习
  12. HDMI热插拔检测原理
  13. [转载]从MyEclipse到IntelliJ IDEA-让你摆脱鼠标,全键盘操作
  14. KEIL MDK的安装(包含HAL库)
  15. 科研小白如何有效下载英文文献和英文书籍?
  16. php性格属于哪类,狗狗性格分为6大类,你家是属哪一类?快来是看聪明型还是粘人型...
  17. 【MySql】mysql之用户管理
  18. Arm 公司推出了 Mbed linux OS
  19. 民办三本,我从3K到15K的一年
  20. 如何有效的招聘技术人员

热门文章

  1. 雷军:小米MIX Alpha不是折叠屏手机,将会很震撼
  2. 苹果全新10.2英寸iPad再爆实锤 或造成史上最乱的iPad产品线
  3. 巨人退场!索尼前CEO平井一夫正式退休 结束35年索尼生涯
  4. 新风口?人造肉第一股表现强劲 股价累计上涨近600%
  5. 移植dropbear 实现ssh远程登录功能
  6. xml文件的创建和插入节点【原创】
  7. 腾讯的一道链表笔试题【总结】
  8. __FILE__, __LINE__, __FUNCTION__
  9. couldn't find libweibosdkcore.so
  10. Spring容器创建流程(7)事件派发机制