【Spring】依赖注入(DI)时常用的注解@Autowired和@Value

目录

1、@Autowired 自动装配

1.1、要实现自动装配不是一定要使用@Autowired

 1.2、@Autowired的特性

(1)首先会根据类型去spring容器中找(bytype),如果有多个类型,会根据名字再去spring容器中找(byname)

(2)如果根据名字还是匹配不到,解决方案为下面两个:

(3)可以写在方法、构造函数、字段、参数上

2、@Value

(1)方式一:直接把值写在@Value中的属性里

(2)方式二:对外部属性(SpringBoot配置文件)文件的引用

(3)SPEL表达式(Spring Expression Language):@Value("#{}")

 

        依赖注入(DI)是一种软件设计模式,旨在降低模块之间的耦合度。其核心思想是将对象之间的依赖关系外部化,使得代码更加灵活、可维护和可测试。在DI模式中,对象不再负责创建它所依赖的对象,而是由外部的容器(通常是框架或容器)负责将依赖的对象注入到目标对象中。框架如Spring提供了DI功能,通过注解、XML配置文件或Java配置类等方式,开发者可以在需要注入的地方指定相应的注解或配置,框架即可自动完成依赖对象的注入,无需手动创建和管理。

1、@Autowired 自动装配

1.1、要实现自动装配不是一定要使用@Autowired

(1)@Bean 方法的参数会自动注入;

(2)构造函数上的参数会自动注入

 1.2、@Autowired的特性

(1)首先会根据类型去spring容器中找(bytype),如果有多个类型,会根据名字再去spring容器中找(byname)

上图中涉及的代码,先看这个代码,后面作为示例会有改动

@Component  //这里配置bean的类型是AutowiredTestService,名字是autowiredTestService
public class AutowiredTestService {
}@Component
public class AutowiredService {//首先会根据类型去spring容器中找(bytype) ,如果有多个类型, 会根据名字再去spring容器中找(byname)//这里会根据类型找到两个bean,一个是通过@Component注解配置的AutowiredTestService类的bean//还有一个是在SpringConfig配置类中通过@Bean注解配置的AutowiredTestService类的bean//然后他再会通过这里注入时的名字:autowiredTestService,//找到通过@Component注解配置的bean(autowiredTestService)@Autowired  //这里注入的类型是AutowiredTestService,名字是autowiredTestServiceAutowiredTestService autowiredTestService;@Overridepublic String toString() {return "AutowiredService{" +"autowiredTestService=" + autowiredTestService +'}';}
}@Configuration
public class SpringConfig {@Bean  //这里配置bean的类型是AutowiredTestService,名字是autowiredTestService2public AutowiredTestService autowiredTestService2(){AutowiredTestService autowiredTestService = new AutowiredTestService();autowiredTestService.setName("@Bean"); //为AutowiredTestService类bean对象中的name属性赋值return  autowiredTestService;}
}@SpringBootTest  //需要加@SpringBootTest注解,否则这里需要自己去获取ioc容器才能从ioc容器中拿bean
public class AutowiredTest {@Autowired  AutowiredService autowiredService;@Testpublic void test01(){System.out.println(autowiredService.toString());}
}

运行结果:因为通过@Component注解配置的AutowiredTestService类bean时,没有为AutowiredTestService类bean对象中的name属性赋值,这里的结果中name等于null,所以这里获取的是通过@Component注解配置的AutowiredTestService类bean

把AutowiredService类中注入的AutowiredTestService的bean名字改为autowiredTestService2

@Component
public class AutowiredService {//首先会根据类型去spring容器中找(bytype) ,如果有多个类型, 会根据名字再去spring容器中找(byname)//这里会根据类型找到两个bean,一个是通过@Component注解配置的bean,名字为autowiredTestService//还有一个是在SpringConfig配置类中通过@Bean注解配置的AutowiredTestService类的bean//然后他再会通过这里注入时的名字:autowiredTestService2,//找到通过@Bean注解配置的bean,并且这个Bean对象中的name属性值为‘@Bean’@Autowired  //这里注入的类型是AutowiredTestService,名字是autowiredTestService2AutowiredTestService autowiredTestService2;@Overridepublic String toString() {return "AutowiredService{" +"autowiredTestService=" + autowiredTestService2 +'}';}
}

运行结果:因为通过@Bean注解配置bean时,为AutowiredTestService类bean对象中的name属性赋值为‘@Bean’,这里的结果中name等于‘@Bean’,所以这里获取的是通过@Bean注解配置的bean

(2)如果根据名字还是匹配不到,解决方案为下面两个:

1)通过@primary设置某一个为主要的,比如:

@Component
@Primary
public class AutowiredTestService {}

2)通过@Qualifier("autowiredtestservice2)告诉spring需要的那个bean的名字,比如:

public class AutowiredService {//首先会根据类型去spring容器中找(bytype) ,如果有多个类型, 会根据名字再去spring容器中找(byname)//容器中有两个AutowiredTestService类的bean,一个是通过@Component注解配置的bean(autowiredTestService)//还有一个是在SpringConfig配置文件中通过@Bean注解配置的bean(autowiredTestService2)//但是这里注入时的名字为autowiredTestService3,那他就会报错,因为根据名字autowiredTestService3,//他不知道应该找通过@Component注解配置的bean还是通过@Bean注解配置的bean,//这时候就需要通过@Qualifier("autowiredtestservice2)告诉spring需要的那个bean的名字@Autowired@Qualifier("autowiredTestService2") AutowiredTestService autowiredTestService3; // 虽然通过注入时的名字:autowiredTestService3找不到,// 但是可以通过@Qualifier中的autowiredTestService2找到@Overridepublic String toString() {return "AutowiredService{" +"autowiredTestService=" + autowiredTestService3 +'}';}
}

3)@Autowired注解有一个required属性,当指定required属性为false时,意味着在容器中找相应类型的bean,如果找不到则忽略,而不报错(这一条是@Inject 和 @Resource 两个注解所没有的功能)。如果去容器中一个都没找到就会报错,通过@autowired(required=false)设置required=false,就不会报错了,比如:

@SpringBootTest  //需要加@SpringBootTest注解,否则这里需要自己去获取ioc容器才能从ioc容器中拿bean
public class AutowiredTest {@Autowired(required = false)  //如果去容器中一个都没找到,设置required=false,就不会报错了AutowiredService autowiredService3;public void testConstructor() {System.out.println(autowiredService3);}
}

(3)可以写在方法、构造函数、字段、参数上

上图中涉及的代码,先看这个代码,后面作为示例会有改动

@Service
public class ProductService {
}@Service
public class StockService {
}@Component
public class AutowiredService {private ProductService productService;private StockService stockService;//当这个构造函数被调用时,ProductService没有加@Autowired注解也会被自动的依赖注入进来public AutowiredService(ProductService productService){System.out.println(productService);this.productService = productService;}}@SpringBootTest  //需要加@SpringBootTest注解,否则这里需要自己去获取ioc容器才能从ioc容器中拿bean
public class AutowiredTest {@AutowiredAutowiredService autowiredService3;@Testpublic void testConstructor() {System.out.println(autowiredService3);}
}

1)构造函数:

如果bean只有一个有参构造函数,就算省略@Autowired,也会自动注入构造函数的参数,比如:

public class AutowiredService {private ProductService productService;private StockService stockService;//当这个构造函数被调用时,ProductService没有加@Autowired注解也会被自动的依赖注入进来public AutowiredService(ProductService productService){System.out.println(productService);this.productService = productService;}}

但是如果有多个有参构造函数,并且没有无参构造函数,就会报错,解决方式为使用@Autowired指定某一个构造函数,就是在要指定的那个构造函数上加@Autowired注解,比如:

public class AutowiredService {private ProductService productService;private StockService stockService;@Autowired  //在要指定的构造函数上加@Autowired注解,这样就不会报错,因为下面还有一个有参构造函数public AutowiredService(ProductService productService){System.out.println(productService);this.productService = productService;}public AutowiredService(ProductService productService, StockService stockService){this.productService = productService;this.stockService = stockService;}}

但是这种构造函数上指定的@Autowired(required=false)会失效

2)参数:

如果想设置构造函数里面的参数为不是必须注入:可以单独去设置,就是在参数那里加@Autowired(required=false),比如:

@Autowired
public AutowiredService(@Autowired(required = false) ProductService productService){System.out.println(productService);this.productService = productService;
}

还可以单独的写在单元测试的方法上

@SpringBootTest  //需要加@SpringBootTest注解,否则这里需要自己去获取ioc容器才能从ioc容器中拿bean
public class AutowiredTest {//    @Autowired(required = false)//    AutowiredService autowiredService3;//@Autowired单独的写在下面的单元测试方法上,这里就不用注入了@Testpublic void testConstructor(@Autowired AutowiredService autowiredService) {System.out.println(autowiredService);}
}

3)方法:

spring会自动调用你的@Autowired的方法并进行自动注入需要的参数

//添加了@Autowired注解后,当Spring实例化完AutowiredService对象后,
@Autowired  //就会调用这个方法ltStockService()来进行自动注入这个方法里面的参数StockService
public void ltStockService(StockService stockService){
this.stockService = stockService;
}//这里用来获取上面调用ltStockService()方法来进行自动注入StockService,并被赋值给stockService后的stockService
public StockService getStockService() {return stockService;
}

2、@Value

注入直接值(基本类型,String、List等)

        自动装配注解@Autowired、@Inject和@Resource 主要的是注入我们通过@Component等注解配置的类的实例对象,比如通过@Component把Student类配置成了bean,那么在Spring容器中就会有student这样的一bean,然后就可以通过自动装配(@Autowired)来去注入一个Student类型的bean,Spring容器就会把这个Student类型的bean注入进来。

        而@Value主要是用于注入一些基本的数据类型,比如Stiring、Integer,还有一些复杂数据类型如Map、Lsit等,因为这些数据类型都是由JDK提供的,不可能说去JDK提供的String这个类上面加一个@Component注解,所以这些数据类型通常用@Value进行注入

(1)方式一:直接把值写在@Value中的属性里

上图中涉及的代码,先看这个代码,后面作为示例会有改动

//自定义类User
@Component  //要使用@Value的话,需要先把当前这个类配置成一个bean
public class User {@Value("张三") //直接把值"张三"写在@Value中的属性里private String name;@Value("24") //直接把值"24"写在@Value中的属性里private Integer age;private Map<String, Integer> score;private List<String> hobbies;@Override //重写了toString()方法public String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", score=" + score +", hobbies=" + hobbies +'}';}
}//测试类ValueTest
@SpringBootTest
public class ValueTest {@Testpublic void Test01(@Autowired User user){System.out.println(user);}}

 运行结果:

(2)方式二:对外部属性(SpringBoot配置文件)文件的引用

像前面那样把值直接写死在@Value上非常不利于后期的更改和维护,所以可以把这些值都写在一个properties文件中,要获取外部的属性文件需要通过@PropertuSource注解指定文件路径,然后在@Value中引用它,比如:

//zhangsan.properties文件
zhangsan.name = zhangsan
zhangsan.age = 24

示例代码:

@Component  //要使用@Value的话,需要先把当前这个类配置成一个bean
@PropertySource("zhangsan.properties")  //要获取外部的属性文件需要通过@PropertuSource指定文件路径 2.@Value("${zhangsan.name}")
public class User {//@Value("张三")@Value("${zhangsan.name}")private String name;//@Value("24")@Value("${zhangsan.age}")private Integer age;private Map<String, Integer> score;//剩下代码和上面一样.....没变}//测试类ValueTest的代码也没变

        在SpringBoot中,有一个默认的properties文件:application.properties,这个文件不需要单独的通过@PropertuSource指定文件路径

        并且在SpringBoot中,如果@Value("${}")的 {} 里面的属性值不存在,就会报错,因为SpringBoot更严格。在Spring中,如果@Value("${}")的 {} 里面的属性值不存在,会将属性名字注入到值中

        默认值机制:例如@Value("${zh.name}"),里面的zh.name不存在的话可以通过冒号设置默认值,更改后为@Value("${zh.name:MoRenZhi}"),zh.name如果不存在就会把 "MoRenZhi"注入到值中

        总结:如果是非SpringBoot配置文件,需要额外通过@PropertySource去指定属性文件的类路径,如果是SpringBoot配置文件(application.properties),就无需额外配置@PropertySource

(3)SPEL表达式(Spring Expression Language):@Value("#{}")

用来注入复杂数据类型Map、Lsit等,示例:

@Component  //要使用@Value的话,需要先把当前这个类配置成一个bean
@PropertySource("zhangsan.properties")  //1.要获取外部的属性文件需要通过@PropertuSource指定类路径 2.@Value("${zhangsan.name}")
public class User {//@Value("张三")@Value("${zhangsan.name}")private String name;//@Value("24")@Value("${zhangsan.age}")private Integer age;@Value("#{{'语文':'90','数学':'100'}}")private Map<String, Integer> score;@Value("#{{'唱歌,打球,写代码'}}")private List<String> hobbies;//剩下代码和上面一样.....}

 

 

推荐: 

【Spring】使用@Bean和@Import注解配置Bean,与Bean的实例化_import和bean-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/137257177?spm=1001.2014.3001.5501

【Spring】分别基于XML、注解和配置类实现Spring的IOC(控制反转)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/137237805?spm=1001.2014.3001.5501

【java多线程】线程池 ThreadPoolExecutor类和Executors工厂类以及线程池的最优大小-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/137673188?spm=1001.2014.3001.5501

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

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

相关文章

springcloud-fegin 组件调用

一、Feign 概述 Feign是Netflix开发的声明式、模板化的HTTP客户端&#xff0c; Feign可以帮助我们更快捷、优雅地调用HTTP API。 在Spring Cloud中&#xff0c;使用Feign非常简单——创建一个接口&#xff0c;并在接口上添加一些注解&#xff0c;代码就完成了。Feign支持多种…

llama-factory SFT系列教程 (二),大模型在自定义数据集 lora 训练与部署

文章目录 简介支持的模型列表2. 添加自定义数据集3. lora 微调4. 大模型 lora 权重&#xff0c;部署问题 参考资料 简介 文章列表&#xff1a; llama-factory SFT系列教程 (一)&#xff0c;大模型 API 部署与使用llama-factory SFT系列教程 (二)&#xff0c;大模型在自定义数…

Day01——NestJS学习之了解、安装、运行

什么是 Nest.js&#xff1f; NestJs 官方简介: Nest (NestJS) 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的开发框架。它利用 JavaScript 的渐进增强的能力&#xff0c;使用并完全支持 TypeScript &#xff08;仍然允许开发者使用纯 JavaScript 进行开发&#x…

leetcode:739.每日温度/496.下一个更大元素

单调栈的应用&#xff1a; 求解当前元素右边比该元素大的第一个元素&#xff08;左右、大小都可以&#xff09;。 单调栈的构成&#xff1a; 单调栈里存储数组的下标&#xff1b; 单调栈里的元素递增&#xff0c;求解当前元素右边比该元素大的第一个元素&#xff1b;元素递…

【Java开发指南 | 第六篇】Java成员变量(实例变量)、 类变量(静态变量)

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 成员变量&#xff08;实例变量&#xff09;类变量&#xff08;静态变量&#xff09;定义方式静态变量的使用场景 成员变量&#xff08;实例变量&#xff09; 成员变量声明在一个类中&#xff0c;但在方法、构造…

【opencv】示例-videocapture_openni.cpp 深度数据获取和处理的示例

该代码是一个与使用OpenCV进行深度传感器捕获和处理相关的程序的一部分。主要功能包括处理Kinect或XtionPRO等深度传感器数据&#xff0c;解析命令行参数&#xff0c;打开视频捕获设备&#xff0c;以及在GUI上显示深度图&#xff0c;彩色图像&#xff0c;和红外图像等。代码中使…

linux 自定义快捷指令(docker

vi /root/.bashrc alias disdocker images alias dpsdocker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" 保存退出后使用sourece /root/.bashrc 让其立即生效 sourece /root/.bashrc

byobu

byobu 终端多路复用器 一、byobu 安装二、byobu 使用三、其他终端多路复用器四、ssh byobu 远程协作 系统环境: linux(ubuntu,debian,kali) 一、byobu 安装 byobu 是包装过的tmux #sudo apt install tmux sudo apt install byobubyobu二、byobu 使用 创建窗口: Ctrl a c…

HashMap的扩容看这一篇足够

在Java中&#xff0c;对于HashMap这样的实现&#xff0c;put方法是用来将一个键值对插入到Map中的核心方法。以下是HashMap类中put方法的大致执行流程&#xff1a; 计算Hash值&#xff1a; 首先&#xff0c;put方法会接收一个键&#xff08;Key&#xff09;和一个值&#xff0…

攻防世界13-simple_php

13-simple_php <?php show_source(*__FILE__*);//高亮文件 include("config.php");//文件包含在内 $a$_GET[a];//获得a $b$_GET[b];//获得b if($a0 and $a){ //判断a是否满足条件echo $flag1; //满足就输出flag1 } if(is_numeric($b)){ //判断b的条件&#x…

Python | Leetcode Python题解之第26题删除有序数组中的重复项

题目&#xff1a; 题解&#xff1a; class Solution:def removeDuplicates(self, nums: List[int]) -> int:if not nums:return 0n len(nums)fast slow 1while fast < n:if nums[fast] ! nums[fast - 1]:nums[slow] nums[fast]slow 1fast 1return slow

Git可视化工具 - 推荐

概述 Git版本管理工具是我们日常开发中常用的工具&#xff0c;熟练使用它可以提高我们的工作效率。 当然老司机基本使用命令行的方式进行操作&#xff0c;新手可借助可视化工具来进行过渡&#xff0c;命令行与可视化工具结合使用来加深对Git的熟悉程度。 下面推荐两个较受欢迎…

MySQL 试图

视图功能在 5.0 以后的版本启用 视图是一张虚表。数据表确实包含了具体数据并且保存到硬盘中的实表。视图使用数据检索语句动态生 成的一张虚表。每一次数据服务重启或者系统重启之后&#xff0c;在数据库服务启动期间&#xff0c;会使用创建视图的语 句重新生成视图中的数据&…

BERT论文解读及情感分类实战

文章目录 简介BERT文章主要贡献BERT模型架构技术细节任务1 Masked LM&#xff08;MLM&#xff09;任务2 Next Sentence Prediction (NSP)模型输入 下游任务微调GLUE数据集SQuAD v1.1 和 v2.0NER 情感分类实战IMDB影评情感数据集数据集构建模型构建超参数设置训练结果注意事项 简…

学习Rust的第三天:猜谜游戏

基于Steve Klabnik的《The Rust Programming Language》一书。今天我们在rust中建立一个猜谜游戏。 Introduction 介绍 We will build a game that will pick a random number between 1 to 100 and the user has to guess the number on a correct guess the user wins. 我们将…

Nginx内存池相关源码剖析(六)外部资源释放和内存池销毁

ngx_destroy_pool函数 先执行回调函数释放所有的外部资源&#xff0c;然后free释放所有的大块内存和小块内存。 // 释放外部资源&#xff0c;销毁内存池 void ngx_destroy_pool(ngx_pool_t *pool) {ngx_pool_t *p, *n;ngx_pool_large_t *l;ngx_pool_cleanup_t *…

用海豚调度器定时调度从Kafka到HDFS的kettle任务脚本

在实际项目中&#xff0c;从Kafka到HDFS的数据是每天自动生成一个文件&#xff0c;按日期区分。而且Kafka在不断生产数据&#xff0c;因此看看kettle是不是需要时刻运行&#xff1f;能不能按照每日自动生成数据文件&#xff1f; 为了测试实际项目中的海豚定时调度从Kafka到HDF…

【计算机网络】常用编码方式+例题(曼彻斯特编码、差分曼彻斯特编码...)

常用编码方式例题 常用编码方式练习画出四种编码20221题342015题342013题34 常用编码方式 练习 画出四种编码 20221题34 这个题目的考察是差分曼彻斯特编码。 差分曼彻斯特编码在每个码元的中间时刻电平都会发生跳变。与曼彻斯特编码不同的是&#xff1a;电平的跳变仅代表时钟…

C++ ─── 操作符重载和赋值重载

目录 赋值运算符重载 运算符重载 赋值运算符重载&#xff08;赋值重载operator&#xff09; 前置和后置重载 赋值运算符重载 运算符重载 C为了增强代码的可读性引入了运算符重载 &#xff0c; 运算符重载是具有特殊函数名的函数 &#xff0c;也具有其返回值类型&#xff0c…

SQL Server 存储函数(funGetId):唯一ID

系统测试时批量生成模拟数据&#xff0c;通过存储函数生成唯一ID。 根据当前时间生成唯一ID&#xff08;17位&#xff09; --自定义函数&#xff1a;根据当前时间组合成一个唯一ID字符串:yearmonthdayhourminutesecondmillisecond drop function funGetId;go--自定义函数&…