spring 属性注入 @Autowired和@Resource注解使用

众所周知@Resource 和 @Autowired两大注解是开发中最常用的两大注解。两者有一定的区别:

@Autowired

@Autowired是spring框架提供的注解类,默认按照类型进行装配。当在容器中找不到对应类型的bean时会抛出NoSuchBeanDefinitionException异常,当存在多个符合条件的bean且没有指定选择策略时会抛出BeanNotOfRequiredTypeException异常。

@Autowired也可以按bean的名称进行装配,这个时候需要借助@Qualifier注解。

@Autowired
@Qualifier("injectServiceA")
private InjectService injectService;

指定注入的InjectService类型的bean名称为injectServiceA。

@Autowired还有一个布尔属性required,默认是true,如果设置成false,找不到对应的依赖不会报错。就需要代码逻辑上来判断是否有当前服务。

@Autowired(required = false)
private InjectService injectService1;
@Resource

@Resource时Java EE提供的注解规范,在 Java EE 容器中同样可以使用。@Resource 默认情况下(未显示指定bean名称)按照名称(name)进行自动装配。如果按照名称找不到会在尝试按类型进行装配。这样看来@Resource相对来说更健壮一些。

@Resource注解可以属性和set方法上。使用在属性上就是按属性名进行寻找bean。

@Resource
private InjectService otherService;

如果要指定名字,可以使用name属性

@Resource(name="injectServiceA")
private InjectService injectService2;

除了使用name属性也可以使用@Qualifier注解指定bean名称。

@Resource
@Qualifier("injectServiceB")
private InjectService injectService3;

也可以指定按类型来装配

@Resource(type = InjectService.class)
private InjectService injectService4;

因为时按照名称进行装配,不会存在多个符合条件的bean,但是会存在类型不匹配问题,抛出BeanNotOfRequiredTypeException异常。

@Primary

不管是@Resource还是@Autowired都存在一个问题,按类型查找时候如果存在多个符合条件的bean就无法完成注入,这个时候可以在被注入的bean上添加@Primary来标识当前bean是多个候选实例中优选选用的bean。找到多个是会优选使用带有@Primary注解的bean。

@Autowired源码分析

没错@Autowired类型的属性注入是通过context初始化时候添加的类后置处理器AutowiredAnnotationBeanPostProcessor来完成的。

在AnnotationConfigApplicationContext容器构造方法初始化reader时候会调用AnnotationConfigUtils.registerAnnotationConfigProcessors来注册processors,这里就会加载注解自动注入的bean后置处理器AutowiredAnnotationBeanPostProcessor。

if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}

AutowiredAnnotationBeanPostProcessor继承自SmartInstantiationAwareBeanPostProcessor。

那么什么时候调用的postProcessor呢,在bean的初始化过程中,创建完实例后就会进行属性注入,主要在 AbstractAutowireCapableBeanFactory#populateBean方法来完成。

//...
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {//是否有InstantiationAwareBeanPostProcessor处理器if (pvs == null) {pvs = mbd.getPropertyValues();}//逐个拿出InstantiationAwareBeanPostProcessor,调用postProcessProperties方法。for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}
}

AutowiredAnnotationBeanPostProcessor#postProcessProperties

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);metadata.inject(bean, beanName, pvs);return pvs;
}

这里首先会根据注解读取所有带有指定注解的bean属性和方法。注解包括@Autowired和@Value。如果支持JSR-330,也包含@Inject注解。 这个是在AutowiredAnnotationBeanPostProcessor的构造函数里初始化的。找到带有对应的注解会封装成InjectedElement对象集合放到InjectionMetadata的injectedElements属性里,是一个注解。然后metadata.inject方法会将injectedElements一一进行注入,调用InjectedElement.inject()方法。

AutowiredFieldElement#inject()主要逻辑

Field field = (Field) this.member;
value = resolveFieldValue(field, bean, beanName);
if (value != null) {ReflectionUtils.makeAccessible(field);field.set(bean, value);
}

最后会调用beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);方法获取依赖的值,这里面就有@Autowired注入根据类型的逻辑。将值设置给field完成依赖注入。

@Resource注解源码分析

@Resource注解的处理过程和@Autowired的过程大致是一致的,只不过其使用的bean处理器是CommonAnnotationBeanPostProcessor。其找到的符合条件的属性封装成ResourceElement extends LookupElement。获取属性值调用CommonAnnotationBeanPostProcessor.getResourceToInject()方法。

这个就留给自己去看吧。

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

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

相关文章

C语言中的结构体成员赋值与访问详解

C语言中的成员赋值与访问 在C语言中,我们可以使用不同的方式对结构体变量的成员进行赋值和访问。本文将详细介绍这些方式,并通过具体的示例代码加以说明。 目录 使用strcpy_s函数赋值字符串直接赋值数字和浮点数结构体变量之间的赋值使用复合文字进行…

周周清(2)----踩坑日记

周一: 1.之前换了一个jdk,然后又改了很多东西,很乱,以至于很多项目都不能直接运行了,所以今天就将ideal删除并且更新版本到2022.3.3,并且重新将ideal里面的配置环境变量,以及jdk下载安装配置&a…

数据库系列之简要对比下GaussDB和OpenGauss数据库

GaussDB作为一款企业级的数据库产品,和开源数据库OpenGauss之间又是什么样的关系,刚开始接触的时候是一头雾水,因此本文简要对比下二者的区别,以加深了解。 1、GaussDB和OpenGauss数据库简要对比 GaussDB是华为基于PostgreSQL数据…

WPF仿网易云搭建笔记(4):信息流控制之消息订阅

文章目录 专栏和Gitee仓库前言消息订阅最简单的案例简单用例父组件订阅子组件回调 结果 消息订阅机制消息token是A还是B?传递消息的载体。双重token重复订阅问题 结论 专栏和Gitee仓库 WPF仿网易云 Gitee仓库 WPF仿网易云 CSDN博客专栏 前言 上一篇文章中,我们简单…

PHP基础(1)

PHP是一种服务器端脚本语言,是一种用于开发动态Web应用程序的最流行和广泛使用的语言之一。它的全称为“Hypertext Preprocessor”,是一种开源的、可嵌入HTML的脚本语言,可以嵌入到HTML中,也可以直接作为命令行脚本运行。PHP脚本在…

Java小案例-如果您的 Java 应用程序在不做任何事情时正在消耗 CPU,您如何确定它在做什么?

前言 我正在调用供应商的 Java API,在某些服务器上,JVM 在登录 API 后似乎进入了低优先级轮询循环(CPU 使用率为 100%)。其他服务器上的同一应用程序不会出现此行为。这发生在 WebSphere 和 Tomcat 上。环境设置起来很棘手&#…

DevOps搭建(四)-GitLab安装细步骤

在这里我们用docker安装 1、创建gitlab安装目录 mkdir -p /usr/local/docker/gitlab_docker 进入该目录 cd /usr/local/docker/gitlab_docker 2、下载gitlab镜像 docker pull gitlab/gitlab-ce:latest 3、创建docker-compose.yml vi docker-compose.yml 输入以下内容保…

理解 HTTP POST 请求:表单与 JSON 数据格式深入解析20231208

引言 在日常的 Web 开发中,理解 HTTP POST 请求的不同数据格式是至关重要的。这不仅有助于构建健壮的后端服务,还能确保与其他服务的有效沟通。本文将深入探讨 multipart/form-data 和 application/json,这两种常见的 POST 请求格式。 POST…

2023 年安徽省职业院校技能大赛高职组“软件测试”赛项样题

2023 年安徽省职业院校技能大赛 高职组“软件测试”赛项样题 目录 任务一:功能测试(45 分) 1、测试计划(5 分) 2、测试用例(15 分) 3、Bug 清单(20 分) 4、测试报告&…

Python 学习笔记之 networkx 使用

介绍 networkx networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用 networkx 中的 Graph Graph 的定义 Graph 是用点和线来刻画离散事物…

张驰咨询:数据驱动的质量改进,六西格玛绿带在汽车业实践

尊敬的汽车行业同仁们,您是否曾面临生产效率低下、成本不断攀升或顾客满意度下降的困扰?本期专栏,我们将深入探讨如何通过六西格玛绿带培训,在汽车行业中实现过程优化和质量提升。 汽车行业的竞争日趋激烈,致力于提供…

3.cloud-Consul服务注册与发现

1.官网 https://learn.hashicorp.com/consul/getting-started/install.html 2.订单服务 2.1 POM <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependenc…

学习Java第66天,路径问题

相对路径情况分析 相对路径情况1:web/index.html中引入web/static/img/logo.png 访问index.html的url为 : http://localhost:8080/web03_war_exploded/index.html 当前资源为 : index.html 当前资源的所在路径为 : http://localhost:8080/web03_war_exploded/ 要获取的目标资…

【华为数据之道学习笔记】3-9元数据治理面临的挑战

华为在进行元数据治理以前&#xff0c;遇到的元数据问题主要表现为数据找不到、读不懂、不可信&#xff0c;数据分析师们往往会陷入数据沼泽中&#xff0c;例如以下常见的场景。 某子公司需要从发货数据里对设备保修和维保进行区分&#xff0c;用来不对过保设备进行服务场景分析…

Qt 使用百度的离线地图

使用百度离线地图&#xff0c;一下载百度离线包&#xff08;offlinemap&#xff09;&#xff1b;二是准备地图瓦片&#xff08;不同级别的瓦片&#xff09;&#xff1b;三 准备&#xff48;&#xff54;&#xff4d;&#xff4c;主页面&#xff1b;四&#xff0c;&#xff31;&…

深度学习 Day13——P2彩色图片分类

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU&#xff08;如果设备上支持GPU就使用GPU,否则使用C…

在Go中定义方法

引言 函数允许你将逻辑组织到可重复的过程中,每次运行时可以使用不同的参数。在定义函数的过程中,你会经常发现多个函数可能每次都操作同一段数据。Go可以识别这种模式,并允许您定义特殊的函数,称为方法,其目的是对某些特定类型的实例进行操作,称为接收器。为类型添加方…

nodejs微信小程序+python+PHP基于spark的酒店管理系统-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

排序算法——归并排序

归并排序&#xff08;Merge Sort&#xff09;是计算机科学中非常重要的排序算法之一。它不仅高效、稳定&#xff0c;而且是许多高级排序技术和算法思想的基础。在本文中&#xff0c;我们将深入探讨归并排序的原理、实现方法&#xff0c;以及它的优缺点。 1. 归并排序的原理 归…

Python大模型TensorFlow/PyTorch/Scikit-learn/Keras/OpenCV/Gensim

Python 作为一种高级编程语言&#xff0c;可以用于开发各种大小的模型。以下是一些常见的 Python 大模型&#xff0c;以及它们的优势、劣势和使用场景&#xff1a; TensorFlow&#xff1a; 优势&#xff1a;TensorFlow 是一个非常流行的深度学习库&#xff0c;具有高度的可扩…