【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,名字是autowiredTestService
    AutowiredTestService autowiredTestService;
    @Override
    public String toString() {
        return "AutowiredService{" +
        "autowiredTestService=" + autowiredTestService +
        '}';
    }
}


@Configuration
public class SpringConfig {

    @Bean  //这里配置bean的类型是AutowiredTestService,名字是autowiredTestService2
    public 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;

    @Test
    public 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,名字是autowiredTestService2
    AutowiredTestService autowiredTestService2;
    @Override
    public 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找到
    @Override
    public 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 {

    @Autowired
    AutowiredService autowiredService3;

    @Test
    public 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单独的写在下面的单元测试方法上,这里就不用注入了

    @Test
    public 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 {

    @Test
    public 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Sony Camera Remote SDK在Windows上的使用

Sony官方提供了相机遥控软件开发包&#xff0c;允许用户自行开发应用软件&#xff0c;实现对相机的远程控制&#xff0c;包括拍摄、监看和文件传输等。截至目前最新的版本是2024.4.12发布的1.12.00版本&#xff0c;下载链接如下&#xff1a;Camera Remote SDK | LICENSE AGREEM…

温湿度传感器(DHT11)以及光照强度传感器(BH1750)的使用

前言 对于一些单片机类的环境检测或者智能家居小项目中&#xff0c;温湿度传感器&#xff08;DHT11&#xff09;以及光照强度传感器&#xff08;BH1750&#xff09;往往是必不可少的两个外设&#xff0c;下面我们来剖析这两个外设的原理&#xff0c;以及使用。 1. 温湿度传感…

elasticsearch 下载、启动和账号密码登录

因为我的电脑是 window&#xff0c;以下都是以 window 环境举例。 一、下载 Elasticsearch 是使用 java 开发的&#xff0c;且 7.8 版本的 ES 需要 JDK 版本 1.8 以上&#xff0c;安装前注意java环境的准备。 官网地址&#xff1a;https://www.elastic.co/cn/ 下载地址&#xf…

云安全与网络安全:有什么区别?

云计算已经存在了一段时间&#xff0c;但某些术语的正确含义仍然存在混乱。一个例子是区分云安全与网络安全。 首先&#xff0c;让我们看一下网络安全一词 &#xff0c;以了解它的含义。然后&#xff0c;我们将将该术语与云安全进行比较&#xff0c;以了解两者在几个关键领域的…

OpenHarmony实战开发-如何使用AKI轻松实现跨语言调用。

介绍 针对JS与C/C跨语言访问场景&#xff0c;NAPI使用比较繁琐。而AKI提供了极简语法糖使用方式&#xff0c;一行代码完成JS与C/C的无障碍跨语言互调&#xff0c;使用方便。本示例将介绍使用AKI编写C跨线程调用JS函数场景。通过调用C全局函数&#xff0c;创建子线程来调用JS函…

DaVinci Fusion Studio:专业影视后期特效合成的得力助手

在当今影视制作领域&#xff0c;后期特效合成是不可或缺的一环。而DaVinci Fusion Studio作为一款功能强大的影视后期特效合成软件&#xff0c;以其出色的性能、直观的操作界面和丰富的特效库&#xff0c;受到了广大影视制作人员的喜爱。 首先&#xff0c;DaVinci Fusion Stud…

使用python在本地指定的目录临时模拟服务器(3),2024年最新网易 面经

先自我介绍一下&#xff0c;小编浙江大学毕业&#xff0c;去过华为、字节跳动等大厂&#xff0c;目前阿里P7 深知大多数程序员&#xff0c;想要提升技能&#xff0c;往往是自己摸索成长&#xff0c;但自己不成体系的自学效果低效又漫长&#xff0c;而且极易碰到天花板技术停滞…

NodeJS特点

NodeJS特点 web服务器的主要特点是&#xff1a;事件驱动&#xff0c;非阻塞I/O&#xff0c;单线程&#xff0c;跨平台自身非常简单&#xff0c;通过通信协议来组织许多node&#xff0c;通过拓展来达成构建大型网络应用的目的。每一个node进程都构成这个网络的一个节点适用于io…

4个步骤:如何使用 SwiftSoup 和爬虫代理获取网站视频

摘要/导言 在本文中&#xff0c;我们将探讨如何使用 SwiftSoup 库和爬虫代理技术来获取网站上的视频资源。我们将介绍一种简洁、可靠的方法&#xff0c;以及实现这一目标所需的步骤。 背景/引言 随着互联网的迅速发展&#xff0c;爬虫技术在今天的数字世界中扮演着越来越重要…

微信小程序wx.getLocation 真机调试不出现隐私弹窗

在小程序的开发过程中&#xff0c;首页中包含要获取用户地理位置的功能&#xff0c;所以在这里的onLoad&#xff08;&#xff09;中调用了wx.getLocation()&#xff0c;模拟调试时一切正常&#xff0c;但到了真机环境中就隐私框就不再弹出&#xff0c;并且出现了报错&#xff0…

浏览器跨标签页通信的方式都有哪些

跨标签页的实际应用场景&#xff1a; 1. 共享登录状态&#xff1a; 用户登录后&#xff0c;多个标签页中需要及时获取到登录状态&#xff0c;以保持一致的用户信息。这种情况&#xff0c;可以使用浏览器的 localStorage 或者 sessionStorage 来存储登录状态&#xff0c;并通过…

无线测温技术在高炉炉壳温度检测中的应用/无线测温监控系统

安科瑞薛瑶瑶18701709087 摘要:应用方便灵活的无线测温和热成像技术对高炉炉壳进行检测&#xff0c;利用热成像进行检测&#xff0c;发现了温度异常区域后对关注部位进行点的检测&#xff0c;预防炉壳的烧穿&#xff0c;对温度数据采集及存储&#xff0c;通过查看历史趋势来对…

树莓派安装Nginx服务结合内网穿透实现无公网IP远程访问

文章目录 1. Nginx安装2. 安装cpolar3.配置域名访问Nginx4. 固定域名访问5. 配置静态站点 安装 Nginx&#xff08;发音为“engine-x”&#xff09;可以将您的树莓派变成一个强大的 Web 服务器&#xff0c;可以用于托管网站或 Web 应用程序。相比其他 Web 服务器&#xff0c;Ngi…

波奇学Linux:ip协议

ip报头是c语言的结构体 报头和有效载荷如何分离&#xff1f; 固定长度四位首部长度 4位版本号就是IPV4 8位服务类型&#xff1a;4位TOS位段和位保留字段 4位TOS分别表示&#xff1a;最小延时&#xff0c;最大吞吐量&#xff0c;最高可靠性&#xff0c;最小成本 给路由器提…

零基础学Python专栏文章导航站

零基础学Python专栏文章导航站 专栏导读零基础入门篇 专栏导读 本文是零基础学Python的文章导航站。专栏分为零基础入门篇、模块篇、网络爬虫篇、Web开发篇、办公自动化篇、数据分析篇… 为了方便专栏订阅者更方便的阅读专栏文章&#xff0c;点击链接即可跳转到具体文章&#…

谷歌浏览器的开发者插件vue-devtools

在这里我留下一个git地址用来下载插件包&#xff0c;首先在自己喜欢的位置创建一个新的文件夹&#xff0c;起一个自己喜欢的文件夹名字&#xff0c;下载到包后&#xff0c;然后点进文件夹里下载依赖&#xff0c;npm install,下载后如下面这个样子 git clone https://gitee.com…

深入详解GRACE CPU架构

深入详解GRACE CPU架构 NVIDIA Grace CPU 是 NVIDIA 开发的第一款数据中心 CPU。 通过将 NVIDIA 专业知识与 Arm 处理器、片上结构、片上系统 (SoC) 设计和弹性高带宽低功耗内存技术相结合&#xff0c;NVIDIA Grace CPU 从头开始构建&#xff0c;以创建世界上第一个超级芯片 用…

00 【哈工大_操作系统】Bochs 汇编级调试方法及指令

本文将介绍一下哈工大李治军老师《操作系统》课程在完成Lab时所使用到的 Bochs 调试工具的使用方法。这是一款汇编级调试工具&#xff0c;打开调试模式非常简单&#xff0c;只需在终端下输入如下指令&#xff1a; 1、bochs 调试基本指令大全 功能指令举例在某物理地址设置断点…

使用API有效率地管理Dynadot域名,撤回域名转移请求

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

MySQL workbench使用教程(逐渐补充版)

附件&#xff1a; 附1&#xff1a;MySQL下载、安装、配置之Windows 附2&#xff1a;MySQL workbench下载、安装、配置、汉化教程 一、 使用 Workbench 操作数据库 1.MySQL Workbench 初始化界面 2.连接远程 MySQL 数据库 3.创建数据库 切换至schemas标签&#xff0c;右键单…