为了搞明白自动装配原理,需要知道spring容器管理bean的生命周期

Spring Bean 生命周期流程图

bean自身方法的生命周期

分为四步:

//执行此段代码,spring容器的bean执行实例化、属性赋值、初始化
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");//关闭容器,执行销毁
classPathXmlApplicationContext.close();

1、实例化

  • 读取spring配置文件
  • 通过反射进行bean的实例化(eg:通过BeanFactory实例化)

2、属性赋值

  • 解析自动装配(byName、byType、constractor、default)DI的体现
  • 循环依赖

3、初始化

  • 调用XXXAware回调方法
  • 调用初始化生命周期回调(三种)
  • 如果bean实现aop创建动态代理

4、销毁

  • 在spring容器关闭的时候进行调用
  • 调用初始化生命周期回调

对应上述文字,下图展示了bean装载到spring应用上下文种的一个典型的生命周期过程

@Autowired注解的自动装配过程

先说结论:

@Autowired是在Bean属性赋值阶段进行装配,通过Bean的后置处理器进行解析

1、在创建一个spring上下文的时候在构造函数中注册AutowiredAnnotationBeanPostProcessor

2、在Bean的创建过程中进行解析

1、在实例化后预解析(解析@Autowired标注的属性、方法,比如:把属性的类型、名称、属性所在的类...元数据缓存)

2、在属性赋值阶段真正的注入(拿到上一步缓存的元数据去ioc容器进行查找,并且返回注入)

a.首先根据解析的元数据拿到类型去容器种查找

*如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;

*如果查询的结果不止一个,那么@Autowired会根据名称来查找

*如果上述查找结果为空,那么就会抛出异常。

大致流程图如下:

@Autowired字段注入源码分析

/* ......源码注解过多,只贴一部分有用的* <h3>Not supported in {@code BeanPostProcessor} or {@code BeanFactoryPostProcessor}</h3>* <p>Note that actual injection is performed through a* {@link org.springframework.beans.factory.config.BeanPostProcessor* BeanPostProcessor} which in turn means that you <em>cannot</em>* use {@code @Autowired} to inject references into* {@link org.springframework.beans.factory.config.BeanPostProcessor* BeanPostProcessor} or* {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor}* types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}* class (which, by default, checks for the presence of this annotation).** @author Juergen Hoeller* @author Mark Fisher* @author Sam Brannen* @since 2.5* @see AutowiredAnnotationBeanPostProcessor* @see Qualifier* @see Value*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {/*** Declares whether the annotated dependency is required.* <p>Defaults to {@code true}.*/boolean required() default true;}

1、重点在注释里的一句:

 Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}

2、AutowiredAnnotationBeanPostProcessor是Spring的后置处理器,专门处理@Autowired和@Value注解。查看AutowiredAnnotationBeanPostProcessor类,关注postProcessMergedBeanDefinition()方法、postProcessPropertyValues()方法和构造器;

//Spring在每个Bean实例化的时候,调用populateBean进行属性注入的时候,即调用postProcessPropertyValues方法。
@Deprecated
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {return postProcessProperties(pvs, bean, beanName);
}//​Spring容器在每个Bean实例化之后,调用AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法。
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);
}//AutowiredAnnotationBeanPostProcessor构造器
public AutowiredAnnotationBeanPostProcessor() {//后置处理器将处理@Autowire注解this.autowiredAnnotationTypes.add(Autowired.class);//后置处理器将处理@Value注解this.autowiredAnnotationTypes.add(Value.class);try {//后置处理器将处理javax.inject.Inject JSR-330注解this.autowiredAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}
}@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {//获取指定类中autowire相关注解的元信息InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {//对Bean的属性进行自动注入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、查看对Bean的属性进行自动注入metadata.inject(bean, beanName, pvs);方法

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

4、查看element.inject(target, beanName, pvs);方法

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)throws Throwable {if (this.isField) {Field field = (Field) this.member;ReflectionUtils.makeAccessible(field);field.set(target, getResourceToInject(target, requestingBeanName));}else {if (checkPropertySkipping(pvs)) {return;}try {Method method = (Method) this.member;ReflectionUtils.makeAccessible(method);method.invoke(target, getResourceToInject(target, requestingBeanName));}catch (InvocationTargetException ex) {throw ex.getTargetException();}}
}

这是element.inject(target, beanName, pvs);的原始方法,它还有两个子类自己实现的方法,如图:

此案例是字段注入分析,查看AutowiredFieldElement

//AutowiredAnnotationBeanPostProcessor.java@Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {//获取要注入的字段Field field = (Field) this.member;Object value;//如果字段的值有缓存if (this.cached) {//从缓存中获取字段值valuevalue = resolvedCachedArgument(beanName, this.cachedFieldValue);}//没有缓存else {//创建一个字段依赖描述符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();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) {//字段值不为null,并且required属性为trueif (value != null || this.required) {this.cachedFieldValue = desc;//为指定Bean注册依赖BeanregisterDependentBeans(beanName, autowiredBeanNames);if (autowiredBeanNames.size() == 1) {String autowiredBeanName = autowiredBeanNames.iterator().next();//如果容器中有指定名称的Bean对象if (beanFactory.containsBean(autowiredBeanName)) {//依赖对象类型和字段类型匹配,默认按类型注入if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {//创建一个依赖对象的引用,同时缓存this.cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName, field.getType());}}}}//如果获取的依赖关系为null,且获取required属性为falseelse {//将字段值的缓存设置为nullthis.cachedFieldValue = null;}//容器已经对当前字段的值缓存this.cached = true;}}}//如果字段值不为nullif (value != null) {//显式使用JDK的反射机制,设置自动的访问控制权限为允许访问ReflectionUtils.makeAccessible(field);//为字段赋值field.set(bean, value);}}

从注解@Value/@Autowired中获取要注入的值,之后利用反射set到字段中。 重点就是怎么从注解中获取要注入的值,我们来看核心代码

value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
//DefaultListableBeanFactory.javapublic Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());if (Optional.class == descriptor.getDependencyType()) {return createOptionalDependency(descriptor, requestingBeanName);}else if (ObjectFactory.class == descriptor.getDependencyType() ||ObjectProvider.class == descriptor.getDependencyType()) {return new DependencyObjectProvider(descriptor, requestingBeanName);}else if (javaxInjectProviderClass == descriptor.getDependencyType()) {return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);}else {Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);if (result == null) {//真正获取值的代码result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);}return result;}}

进行跟踪:

//DefaultListableBeanFactory.javapublic Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {Object shortcut = descriptor.resolveShortcut(this);if (shortcut != null) {return shortcut;}//获取字段属性的类型Class<?> type = descriptor.getDependencyType();//拿到@Value里的值Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);if (value != null) {if (value instanceof String) {String strVal = resolveEmbeddedValue((String) value);BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);value = evaluateBeanDefinitionString(strVal, bd);}TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());return (descriptor.getField() != null ?converter.convertIfNecessary(value, type, descriptor.getField()) :converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));}//如果标识@Autowired注解的属性是集合类型,Array,Collection,Map,// 从这个方法获取@Autowired里的值
<1>       Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}//如果标识@Autowired注解的属性是非集合类型,// 从这个方法获取@Autowired里的值
<2>       Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);//如果没有符合该类型的Beanif (matchingBeans.isEmpty()) {//是否是必须的if (isRequired(descriptor)) {//抛出异常raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}String autowiredBeanName;Object instanceCandidate;//如果符合该类型的Bean有多个if (matchingBeans.size() > 1) {//挑选出最优解
<3>           autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);if (autowiredBeanName == null) {if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {//抛出异常return descriptor.resolveNotUnique(type, matchingBeans);}else {// In case of an optional Collection/Map, silently ignore a non-unique case:// possibly it was meant to be an empty collection of multiple regular beans// (before 4.3 in particular when we didn't even look for collection beans).return null;}}instanceCandidate = matchingBeans.get(autowiredBeanName);}else {// We have exactly one match.Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();autowiredBeanName = entry.getKey();instanceCandidate = entry.getValue();}if (autowiredBeanNames != null) {autowiredBeanNames.add(autowiredBeanName);}if (instanceCandidate instanceof Class) {instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);}Object result = instanceCandidate;if (result instanceof NullBean) {if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}result = null;}if (!ClassUtils.isAssignableValue(type, result)) {throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());}return result;}finally {ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);}}

大致流程就是: 根据字段类型从IOC容器中获取符合的Bean,如果有多个,则挑选出最优的那一个。

<1>处:@Autowired注入集合数组,如Map.List。

<2>处:@Autowired注入非集合数组,即普通的类如Service

<3>处:多个同类型的bean中挑选出最优解

总结:

在容器启动,为bean属性赋值的时候,spring会用后置处理器AutowiredAnnotationBeanPostProcessor解析@Autowired注解,来创建属性的实例,然后从IOC容器中根据@Primary、@Order、@PriorityOrder或Spring默认规则挑选出最符合的Bean,利用反射注入到字段中完成赋值;

spring自动装配原理相关推荐

  1. Spring自动装配原理理解

    Spring本质上就是一个管理程序应用的容器,而spring的一个核心功能就是自动装配,也就是在程序启动时就自动将应用所需的所有bean自动扫描.配置和装入到容器中去,方便程序的使用. 什么是Spri ...

  2. Java的注解机制——Spring自动装配的实现原理

    JDK1.5加入了对注解机制的支持,实际上我学习Java的时候就已经使用JDK1.6了,而且除了@Override和@SuppressWarnings(后者还是IDE给生成的--)之外没接触过其他的. ...

  3. Spring Boot自动装配原理详解

    目录 1.环境和依赖 1.1.spring boot版本 1.2.依赖管理 2.自动装配 2.1.流程概述 2.2.三大步前的准备工作 2.2.1.注解入口 2.2.2.获取所有配置类 2.3.获取过 ...

  4. 【SpringBoot】自动装配原理

    [SpringBoot]自动装配原理 文章目录 [SpringBoot]自动装配原理 一.pom.xml 1.spring-boot-dependencies 2.spring-boot-starte ...

  5. springboot 整合redis_springboot自动装配原理详解

    1)传统ssm整合redis的时候 需要在xml的配置文件中 进行大量的配置Bean 我们在这里使用springboot来代替ssm的整合,只是通过xml的形式来整合redis 第一步:加入配置 &l ...

  6. 一步一步手绘Spring DI运行时序图(Spring 自动装配之依赖注入)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  7. 【理解springboot自动装配原理】

    理解springboot自动装配原理: 最近读了小马哥(mercyblitz)Springboot编程思想(核心篇),有了一些心得和感悟,分享给大家: 1. 官网介绍了激活自动装配的方法: * 文档提 ...

  8. SpringBoot自动装配原理浅析

    Springboot自动装配原理 SpringBoot是当下J2EE最为流行的框架,它有着轻量,快捷等特点,让程序员们可以专注在业务逻辑的编写上,而不用花太多的力气在一些环境的配置,整合组件的配置上面 ...

  9. 第六篇 Spring 自动装配

    <Spring>篇章整体栏目 ----------------------------- [第一章]spring 概念与体系结构 [第二章]spring IoC 的工作原理 [第三章]sp ...

最新文章

  1. 用python处理excel数据的优势-python处理excel的优势是什么
  2. android线程间通信的几种方法_Android 技能图谱学习路线
  3. 【C++】异常 Exception
  4. 关于windows图形编程 Hello2 程序的问题
  5. ubuntu 目录及文件权限 000 444 666 777(转)
  6. sys/queue.h分析(图片复制不过来,查看原文)
  7. Leetcode刷题(2)回文数
  8. 案例:演示<jsp:include>动作元素
  9. linux的yum命令无法使用在哪里下载_Linux 知识分享:为Linux的cp和mv命令添加进度条...
  10. Maven学习总结(47)——Maven常用命令再总结
  11. C++实现由二元组建立图的邻接表
  12. html选择符分几类,css的选择符有哪些?
  13. php 字符串长度判断_php 字符串长度判断更高效的方法
  14. 加载对话框Android,Android实现加载对话框
  15. 企业支付宝转账到个人银行卡(免费率 无限额)JAVA配置示例
  16. 用java输出一个心型图案_开发工程师的浪漫--java打印心形图案
  17. 联发科:上半年营收2980亿台币,下半年全面发力5G芯片,并布局6G
  18. 基于Kaldi下babel项目的语音关键词检索(KWS)
  19. 2033-人见人爱A+B(java)
  20. 单位dB(分贝)的含义和好处,dBm(dBmW 分贝毫瓦)的含义

热门文章

  1. 使用谷歌提供的html5shiv.js解决
  2. 解决重复提交问题(前端和后端的解决方案java版)
  3. 31.最特殊的快捷键 Alt + Enter 介绍(新用户必看)
  4. Unity3D 2021.1.2F1 发布了。赋国际版本下载地址。
  5. 真实图形学(光照模型)
  6. 捡到的苹果手机怎么解id锁_苹果手机换id通讯录怎么恢复?超详细教程,你值得拥有!...
  7. qq登录超时且二维码加载失败
  8. 【理论】操作系统导论
  9. Flash(Flex)对文件下载进度的监控原理分析
  10. 史上最全C语言学习笔记