SpringBoot自动注入源码分析

Spring Boot何时注入@Autowired标注的属性?

  • 是在Bean实例化后,填充Bean的时候注入@Autowired标注的属性

如果注入类型的Bean存在多个,Spring Boot是如何处理的?

  • 如果存在多个类型的Bean,会根据primary—>javax.annotation.Priority—>名称依次过滤,得到最终匹配的bean名称

一、定义接口

public interface PersonService{String hello(String name);
}

二、定义接口的两个实现

@Service(value = "studentService")
public class StudentServiceImpl implements PersonService{@Overridepublic String hello(String name){return "[student service] hello " + name;}
}
@Service(value = "teacerService")
public class TeacherServiceImpl implements PersonService{@Overridepublic String hello(String name){return "[teacher service] hello " + name;}
}

三、定义控制器

@RestController
public class TestController{@Autowiredprivate PersonService studentService;@Autowiredprivate PersonService teacherService;@GetMapping("/hello")public String hello(@RequestParam(name = "name") String name){return studentService.hello(name) + "=======>" + teacherService.hello(name);}
}

分析

在TestController类上打一个断点,然后查看调用链。
基于调用链路,我们看到有一个doCreateBean方法,该方法就是用来创建bean的
在这里插入图片描述

实例化Bean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {// 创建beaninstanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();// ...省略部分代码// Initialize the bean instance.Object exposedObject = bean;try {// 填充bean,也就是我们上面提到的调用对象的set方法设置对象属性populateBean(beanName, mbd, instanceWrapper);exposedObject = initializeBean(beanName, exposedObject, mbd);}// ...省略部分代码return exposedObject;
}

填充bean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// ...省略代码PropertyDescriptor[] filteredPds = null;if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}// 遍历所有的后置处理器for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;// 通过断点分析我们可以得知此处调用的是AutowiredAnnotationBeanPostProcessor#postProcessPropertiesPropertyValues 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;}}}if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}checkDependencies(beanName, mbd, filteredPds, pvs);}if (pvs != null) {applyPropertyValues(beanName, mbd, bw, pvs);}
}

处理属性

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {// 查找当前bean需要注入的元数据信息,以TestController为例,那么需要注入的就是studentService和teacherService两个属性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;
}

注入属性 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {// 获取属性,此处的属性就是studentServiceField field = (Field) this.member;// 属性对应的valueObject value;if (this.cached) {value = 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) {if (value != null || this.required) {this.cachedFieldValue = desc;registerDependentBeans(beanName, autowiredBeanNames);if (autowiredBeanNames.size() == 1) {String autowiredBeanName = autowiredBeanNames.iterator().next();if (beanFactory.containsBean(autowiredBeanName) &&beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {this.cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName, field.getType());}}}else {this.cachedFieldValue = null;}this.cached = true;}}}if (value != null) {ReflectionUtils.makeAccessible(field);// 给属性设置值,完成注入功能field.set(bean, value);}
}

解析属性依赖 DefaultListableBeanFactory#resolveDependency

public 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 Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);}else {Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);if (result == null) {// 解析依赖result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);}return result;}
}

解析属性依赖 DefaultListableBeanFactory#doResolveDependency

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {// ...省略代码// 解析多个Bean,比如Array、List、Map类型,有兴趣可以自己查看分析Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}// 根据类型获取候选对象,针对studentService而言,该属性的类型为PersonService// PersonService有2个实现类,StudentServiceImpl和TeacherServiceImpl// 所以此处获取结果为StudentServiceImpl对象和TeacherServiceImpl对象Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);if (matchingBeans.isEmpty()) {if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}String autowiredBeanName;Object instanceCandidate;// 重点处理,如果存在多个匹配的beanif (matchingBeans.size() > 1) {// 从已经匹配的bean中选择一个符合的beanautowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);if (autowiredBeanName == null) {// 如果bean必须注入或者存在多个匹配的bean,则抛出异常if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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;}}// 根据bean名称获取对应的示例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);}
}

此处主要根据类型获取所有匹配的bean,如果匹配的bean有多个,那么最后会选择一个符合条件的bean名称,然后将对应的bena实例返回,调用set方法进行进行注入,到此注入的原理本该结束了。

选择符合条件的bean DefaultListableBeanFactory#determineAutowireCandidate

  • 依据Bean的primary属性
  • 依据javax.annotation.Priority
  • 依据注入属性的名称
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {Class<?> requiredType = descriptor.getDependencyType();// 如果bean对应的primary属性为true,则返回bean对应的名称String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);if (primaryCandidate != null) {return primaryCandidate;}// 如果候选bean使用javax.annotation.Priority标注,返回高优先级bean对应的名称String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);if (priorityCandidate != null) {return priorityCandidate;}// Fallback// 如果匹配bean的名称和需要注入的属性名称一致,则返回匹配bean的名称for (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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/479580.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis典型应用之分布式锁

目录 前言 分布式锁的基础实现 引入过期时间&#xff1a; 引入校验ID&#xff1a; 引入lua lua的简介&#xff1a; 引入看门狗 &#xff08;watch dog&#xff09; 引入Redlock算法 前言 在一个分布式系统中&#xff0c;也会涉及到多个节点同时去访问一个公共资源的时候&am…

ArcGIS API for JavaScript 4.X 本地部署(js,字体)

0 目录&#xff08;4.19&#xff09; /4.19/ 1 修改文件 1.1 init.js 编辑器打开/4.19/init.js搜索文本[HOSTNAME_AND_PATH_TO_JSAPI]&#xff0c;然后将其连同前面的https://替换为http://ip地址/4.19&#xff0c;可以是localhost&#xff0c;只能本机引用 替换后&#xff…

Selenium 自动化测试—如何搭建自动化测试环境

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 最近也有很多人私下问我&#xff0c;selenium学习难吗&#xff0c;基础入门的学习内容很多是3以前…

【linux】体系结构和os管理

冯诺依曼体系结构 输入单元&#xff1a;包括键盘, 鼠标&#xff0c;扫描仪, 写板等 中央处理器(CPU)&#xff1a;含有运算器和控制器等 输出单元&#xff1a;显示器&#xff0c;打印机等 这里的存储器指的是内存 三者是相互连接的&#xff0c;设备之间会进行数据的来回拷贝&am…

社区店经营全攻略:如何选址、运营并打造火爆生意?

随着电商的兴起&#xff0c;实体店的经营面临着越来越多的挑战。然而&#xff0c;社区店依然具有独特的优势&#xff0c;如便捷的地理位置、与消费者的紧密互动等。 作为在社区店开鲜奶吧5年的创业者&#xff0c;我深有感触&#xff0c;那么这篇文章将为你提供最有价值的干货信…

计算机设计大赛 深度学习人体跌倒检测 -yolo 机器视觉 opencv python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的人体跌倒检测算法研究与实现 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满…

深入浅出JVM(一)之Hotspot虚拟机中的对象

本篇文章思维导图 对象的创建 对象的创建可以分为五个步骤:检查类加载,分配内存,初始化零值,设置对象头,执行实例构造器 类加载检查 HotSpot虚拟机遇到一条new指令,会先检查能否在常量池中定位到这个类的符号引用,检查这个类是否类加载过 没有类加载过就去类加载类加载过就进…

基于Java+SpringBoot的旅游路线规划系统(源码+论文)

文章目录 目录 文章目录 前言 一、功能设计 二、功能实现 1.1 前端首页模块的实现 1.2 景点新闻 1.3 景点在线预订 1.4 酒店在线预订 1.5 管理员景点管理 1.6 管理员旅游线路管理 1.7 酒店信息管理 三、库表设计 前言 随着我国的经济的不断发展&#xff0c;现在的一些热门的景…

【C++】类与对象(构造函数、析构函数、拷贝构造函数、常引用)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;http://t.csdnimg.cn/eCa5z 目录 类的6个默认成员函数 构造函数 特性 析构函数 特性 析构的顺序 拷贝构造函数 特性 常引用 前言 &…

HBase 进阶

参考来源: B站尚硅谷HBase2.x 目录 Master 架构RegionServer 架构写流程MemStore Flush读流程HFile 结构读流程合并读取数据优化 StoreFile CompactionRegion Split预分区&#xff08;自定义分区&#xff09;系统拆分 Master 架构 Master详细架构 1&#xff09;Meta 表格介…

光芒绽放:妙用“GLAD原则”打造标准的数据可视化图表

光芒绽放&#xff1a;妙用“GLAD原则”打造标准的数据可视化图表 文章目录 光芒绽放&#xff1a;妙用“GLAD原则”打造标准的数据可视化图表前言一、可视化工具有哪些&#xff1f;二、那如何做出正确可视化图表 &#xff1f;GLAD原则1.G原则2.L原则3.A原则4.D原则 三、总结最后…

模式匹配这么好,Java语法里有吗?

这篇文章我们借助新版Java来理解模式匹配&#xff0c;Rust版的模式匹配稍后就端上来&#xff0c;各位先尝尝Java这杯老咖啡还香不香&#x1f604;。 什么是模式匹配&#xff1f; 下图直观的表达了模式匹配的概念。 所谓模式类似上图中木盒的各种形状的洞洞&#xff0c;我们…