Spring @Autowired 注解自动注入流程是怎么样?
面试中碰到面试官问:”Spring 注解是如果工作的?“,当前我一惊,完了这不触及到我的知识误区了吗?,还好我机智,灵机一动回了句:Spring 注解的工作流程倒还没有看到,但是我知道@Autowired注解的工作流程,后面不用说了一顿巴拉,面试官都连连点头。
面试中要活用转移话题,要避免回答 ”不知道“,要引导面试官掉入你擅长的技术,然后才有机会教他作人。
@Autowired 相关的类
@Autowired 注解的主要功能就是完成自动注入,使用也非常简单(Spring都安排好了),但是要想知道 @Autowired 注解的内部现实,就需要看一下Spring源码了。接下来一步步的解剖 @Autowired 的实现原理,首先理一下与 @Autowired 注解相关的类,然后一步步的跟踪源码,直到理解 @Autowired 的原理。
AutowiredAnnotationBeanPostProcessor 类
AutowiredAnnotationBeanPostProcessor是实现  @Autowired 功能的主要类,它有一些方法是会用解析  @Autowired 注解并实现自动注入的功能,下面是它的继承图:

从上图可以发现 AutowiredAnnotationBeanPostProcessor 最上层是  BeanPostProcessor  是一个后处理器,当然除了后处理器外中间还有InstantiationAwareBeanPostProcessor和MergedBeanDefinitionPostProcessor:
InstantiationAwareBeanPostProcessor 接口
postProcessBeforeInstantiation方法
在Bean实例化之前调用,可以返回一个Bean实例,默认返回null。
@Nullabledefault Object postProcessBeforeInstantiation(Class<?> beanClass, String
beanName) throws BeansException {      return null;}
postProcessAfterInstantiation方法
在Bean创建完成后,设置属性之前调用。
default boolean postProcessAfterInstantiation(Object bean, String
beanName) throws BeansException {      return true;}
postProcessProperties方法
@Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object
bean, String beanName)            throws BeansException {      return null;}
Bean创建完后,设置属性之前调用
先记住 InstantiationAwareBeanPostProcessor 接口,后面会跟踪调用它的地方,就很容易理解了。
MergedBeanDefinitionPostProcessor
MergedBeanDefinitionPostProcessor 也是一个继承 BeanPostProcessor 接口的后处理器,它的主要作用就是可以处理操作BeanDefinition对象,由于Bean的实例化是通过 BeanDefinition 的, 通过操作BeanDefinition ,这样可以使Bean的实例化时发生一些变化。
MergedBeanDefinitionPostProcessor 只有两个方法
postProcessMergedBeanDefinition方法
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
Class<?> beanType, String beanName);
Bean的BeanDefinition 被合并后调用此方法。
resetBeanDefinition
default void resetBeanDefinition(String beanName) {}
当一个BeanDefinition被重置后调用 。
AutowireCapableBeanFactory 接口
AutowireCapableBeanFactory继承自BeanFactory,除了提供基础的Bean操作外,从接口的名字就可以推断出的它还有自动注入的能力。AutowireCapableBeanFactory 提供四种注入模型:
- AUTOWIRE_NO: 没有显示的定义注入模型
- AUTOWIRE_BY_NAME: 通过Bean名称注入
- AUTOWIRE_BY_TYPE: 通过Bean的类型注入
- AUTOWIRE_CONSTRUCTOR:通过Bean的构造方法注入
AutowireCapableBeanFactory 接口有不少方法,但大部分都是跟自动注入的相关。@Autowired 的主要功能就是在Bean实例化后,为其设置属性,所以在 AutowireCapableBeanFactory 接口有一个 createBean方法,用于创建Bean并设置Bean的属性:
<T> T createBean(Class<T> beanClass) throws BeansException;
createBean方法,它的调用时机是创建Bean的时候,稍后会说到它的调用时机。
AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactory 继承 AbstractBeanFactory并实现了AutowireCapableBeanFactory接口,所以它也实现了AutowireCapableBeanFactory中的createBean方法。
public <T> T createBean(Class<T> beanClass) throws BeansException {     
// Use prototype bean definition, to avoid registering bean as dependent bean.      
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE);     
bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());      
return (T) createBean(beanClass.getName(), bd, null);}
Bean创建的生命周期
通过了解Bean创建的生命周期,才可以将上面与 @Autowired 相关的类串起来,首先这里不会过多的介绍Bean的创建细节,只关注自动注入相关的代码。
Bean的创建过程
Spring中默认的Bean都是懒加载的,所以一个Bean的创建会从调用getBean方法开始,如果不考虑缓存、上层容器的情况,Bean的创建会经过以下方法:
- getBean:BeanFactory的方法,获取Bean实例
- doGetBean:获取Bean的实例,获取顺序依次为:单例池、父容器,如果从以上2种途径都没获取到Bean实例就会创建新的
- createBean:创建 Bean,这里的createBean,跟上面介绍的是一回事
- doCreateBean:创建Bean实例
- populateBean:设置Bean属性
以上流程中的getBean和doGetBean不多作说明了, 重点关注createBean前面提到AbstractAutowireCapableBeanFactory.createBean方法,所以说你在调用getBean方法获取Bean的实例时,如果这个Bean实例还没有被创建,那么createBean就会被调用。
通过简单的说明Bean创建的生命周期,就能找到 @Autowired 注解实现的入口,接下来再继续跟踪createBean方法。
收集注入元信息
收集注入元信息的步骤的,其实就是调用AutowiredAnnotationBeanPostProcessor类方法来实现的。
Bean 创建之前
以下是createBean方法,在Bean创建之前调用postProcessBeforeInstantiation的地方。为是阅读方便省略了一些代码,大致的流程就是:
- 首先调用 resolveBeforeInstantiation方法,执行InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法
- 如果postProcessBeforeInstantiation返回Bean实例那么直接返回这个实例,如果返回nul 继续调用doCreateBean
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   ...
   try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
        ...
   }
     ...
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    ...
   ...
 }
 @Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
         Class<?> targetType = determineTargetType(beanName, mbd);
         if (targetType != null) {
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) {
               bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
         }
      }
      mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
}
这里 AutowiredAnnotationBeanPostProcessor 的 postProcessBeforeInstantiation 的方法会被调用,由于AutowiredAnnotationBeanPostProcessor 并没有重写这个方法,所以什么都不做。
操作 BeanDefinition
上面说过 postProcessBeforeInstantiation 方法返回 null 的话会继续执行doCreateBean方法:
 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {
   // Allow post-processors to modify the merged bean definition.
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Post-processing of merged bean definition failed", ex);
         }
         mbd.postProcessed = true;
      }
   }
  ...
 populateBean(beanName, mbd, instanceWrapper);
 ...
在 doCreateBean 方法中,会调用调用applyMergedBeanDefinitionPostProcessors方法:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof MergedBeanDefinitionPostProcessor) {
         MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
         bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
   }
MergedBeanDefinitionPostProcessor接口上面提到到的,AutowiredAnnotationBeanPostProcessor 实现了这个接口所以直接进入到 AutowiredAnnotationBeanPostProcessor 中的 postProcessMergedBeanDefinition方法:
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}
查找注入元数据
接着继续进入到findAutowiringMetadata,findAutowiringMetadata 会调用buildAutowiringMetadata方法创建注入元数据,然后将元数据缓存到injectionMetadataCache属性中:
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)) {
            ...
            metadata = buildAutowiringMetadata(clazz);
            this.injectionMetadataCache.put(cacheKey, metadata);
         }
      }
   }
   return metadata;
}
创建注入元数据
仔细查看buildAutowiringMetadata方法的实现,它会反射类的方法和属性,同时还会向上查找父类,然后生成InjectionMetadata。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		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<>();
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				MergedAnnotation<?> 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;
				}
				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);
					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);
	}
小结
收集注入元数据过程,首先调用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法,然后调用findAutowiringMetadata方法查找元数据,如果找到相应类的注入元数据 ,就会调用buildAutowiringMetadata方法创建InjectionMetadata,最后将新创建的注入元数据保存在injectionMetadataCache缓存起来。
设置Bean属性
收信完注入元数据后,Bean的属性还是没有注入的,还需要将执行属性注入。还是在doCreateBean方法中,收集完注入元数据后,紧接着会调用populateBean:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
   if (pvs == null) {
      pvs = mbd.getPropertyValues();
   }
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
         if (pvsToUse == null) {
            if (filteredPds == null) {
               filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               return;
            }
         }
         pvs = pvsToUse;
      }
   }
   }
}
可以看到在populateBean中会调用InstantiationAwareBeanPostProcessor.postProcessProperties方法,由于已经知道 AutowiredAnnotationBeanPostProcessor 是实现 InstantiationAwareBeanPostProcessor 的,所以可以直接查看实现方法:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
   try {
      metadata.inject(bean, beanName, pvs);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
   }
   return pvs;
}
postProcessProperties就很简单的,查找 InjectMetadata,然后调用 InjectMetadata.inject方法。到这里其实就已经知道@Autowire的实现机制了,接下来就是根据InjectionMetadata中的信息实现属性注入了。
如果需要深入研究的话,有兴趣的还可以继续往下看。
总结
本文大致讲解了 @Autowire 相关的类与实现的机制,@Autowire 注解的实现主要是理解AutowiredAnnotationBeanPostProcessor类,还有收集注入元数据、设置注入属性的调用时机。
通过查看AutowiredAnnotationBeanPostProcessor类源码,相信你也可以自定义注入功能。
本人知识水平有限,如有错误,谢谢大家指正。
欢迎关注我的公众号:架构文摘,获得独家整理120G的免费学习资源助力你的架构师学习之路!
公众号后台回复
arch028获取资料:

Spring @Autowired 注解自动注入流程是怎么样?的更多相关文章
- Spring学习(六)-----Spring使用@Autowired注解自动装配
		Spring使用@Autowired注解自动装配 在上一篇 Spring学习(三)-----Spring自动装配Beans示例中,它会匹配当前Spring容器任何bean的属性自动装配.在大多数情况下 ... 
- 解决Spring+Quartz无法自动注入bean问题
		问题 我们有时需要执行一些定时任务(如数据批处理),比较常用的技术框架有Spring + Quartz中.无奈此方式有个问题:Spring Bean无法自动注入. 环境:Spring3.2.2 + Q ... 
- Spring @Autowired 注解 学习资料
		Spring @Autowired 注解 学习资料 网址 Spring @Autowired 注解 https://wiki.jikexueyuan.com/project/spring/annota ... 
- Spring@Autowired注解与自动装配
		1 配置文件的方法 我们编写spring 框架的代码时候.一直遵循是这样一个规则:所有在spring中注入的bean 都建议定义成私有的域变量.并且要配套写上 get 和 set方法. Boss ... 
- 【转】Spring@Autowired注解与自动装配
		1 配置文件的方法 我们编写spring 框架的代码时候.一直遵循是这样一个规则:所有在spring中注入的bean 都建议定义成私有的域变量.并且要配套写上 get 和 set方法. Boss ... 
- Spring Boot @Autowired 没法自动注入的问题
		Application 启动类: @SpringBootApplication @EnableConfigurationProperties @ComponentScan(basePackages = ... 
- Spring@Autowired注解与自动装配(转发)
		1 配置文件的方法 我们编写spring 框架的代码时候.一直遵循是这样一个规则:所有在spring中注入的bean 都建议定义成私有的域变量.并且要配套写上 get 和 set方法. Boss ... 
- [转] Spring@Autowired注解与自动装配
		1 配置文件的方法 我们编写spring 框架的代码时候.一直遵循是这样一个规则:所有在spring中注入的bean 都建议定义成私有的域变量.并且要配套写上 get 和 set方法. Boss ... 
- Spring基于注解自动装配
		前面我们介绍Spring IoC装载的时候,使用XML配置这种方法来装配Bean,这种方法可以很直观的看到每个Bean的依赖,但缺点也很明显:写起来非常繁琐,每增加一个组件,就必须把新的Bean配置到 ... 
随机推荐
- sql server 2008 r2 直接下载地址,可用迅雷下载
			sqlserver 2008 r2 直接下载地址,可用迅雷下载 下载sqlserver 2008 r2 ,微软用了一个下载器,经过从下载器上,将他的地址全部用键盘敲了下来.最终的简体中文版地址如下: ... 
- nrm切换npm源
			使用 nrm 提供了一些最常用的npm包镜像地址,能够让我们快速的切换安装包时候的服务器地址: 全局安装nrm包 npm i nrm -g 查看当前所有可用的镜像源地址以及当前所使用的镜像源地址 nr ... 
- CocoaFoundation和CoreFoundation之间数据转换(桥接__bridge)
			ARC仅管理Objective-C指针(retain.release.autorelease),不管理CoreFoundation指针,CF指针由人工管理,手动的CFRetain和CFRelease来 ... 
- StringUtils工具类(Apache lang3 )
			引入依赖 <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons- ... 
- MapReduce工作原理详解
			文章概览: 1.MapReduce简介 2.MapReduce有哪些角色?各自的作用是什么? 3.MapReduce程序执行流程 4.MapReduce工作原理 5.MapReduce中Shuffle ... 
- 手撸ORM浅谈ORM框架之Update篇
			快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ... 
- 校招“避雷针”——GitHub 热点速览 Vol.43
			作者:HelloGitHub-小鱼干 如果要选一个关键词来概述本周的 GitHub Trending,保护 便是不二之选.先是有 ShameCom 来为应届毕业生护航,让学弟学妹们不被黑名单上的公司上 ... 
- 分区表的表进行update操作
			今天对一张创建了分区表的表进行update操作,正好需要修改的是创建分区的那一列,由于是要修改在分区表范围内的数据,所以无法修改. 然后搜了一下,需要修改row movement这个属性:alter ... 
- 隐马尔科夫模型 HMM(Hidden Markov Model)
			本科阶段学了三四遍的HMM,机器学习课,自然语言处理课,中文信息处理课:如今学研究生的自然语言处理,又碰见了这个老熟人: 虽多次碰到,但总觉得一知半解,对其了解不够全面,借着这次的机会,我想要直接搞定 ... 
- Luogu P4208 [JSOI2008]最小生成树计数
			题意 给定一个 \(n\) 个点 \(m\) 条边的图,求最小生成树的个数. \(\texttt{Data Range:}1\leq n\leq 100,1\leq m\leq 10^4\) 题解 一 ... 
