【Spring】注解读取和存储Bean对象(下)

news2024/11/25 4:53:10

三、Spring 获取 bean 对象

获取 bean 对象也叫 “对象装配”,“对象注入”, 意思就是把对象取出来放到某个类中。

对象装配(对象注入)的实现有以下三种方法:

1. 属性注入  2. 构造方法注入 3. Setter 注入

接下来博主将围绕着3种方式展开来给大家讲述Spring 如何实现动态注入 bean 对象(运行时动态的将 bean 对象注入到某个类中)。

3.1 属性注入

属性注入需要使用到 @Autowired 注解实现。接下来给大家举一个例子:

有一个学生类(学生信息的组织),假设对应数据库中的学生表,有一个Service 层的 StuService类,这类可以从数据库中读取学生数据(增删查改),实例成一个完整的学生对象,有一个 StuController 类,他可以针对学生数据进行实际的使用(调用处理),所以 StuController 类在运行中需要获取到 StuService 类的实例对象来操作数据库中的学生表。当然这里不会给大家真的用数据库,写伪代码来模拟一下真实的环境。

@Service
public class StuService {
    /**
     * 根据学生id从数据库中获取学生信息
     * @param id
     * @return
     */
    public Student getStu(String id) {
        //伪代码,链接数据库,查找学生信息
        Student stu = new Student();
        stu.setId(id);
        stu.setName("张三");
        stu.setAge(18);
        stu.setSex("男");
        return stu;
    }
}
@Controller
public class StuController {
    //1. 属性注入,从Spring 中取出 StuService 类型的bean 对象并注入到类引用中
    @Autowired
    private StuService stuService;

    //2. 调用注入的 bean 对象执行查询操作
    public Student getStu(String id) {
        return stuService.getStu(id);
    }
}

获取 Controller 中的 getStu 的方法:正常情况下我们就将 Student 学生的信息转换为 json 格式由前端发请求,服务器做出响应,将数据(http协议)给到前端,前端利用数据构建页面。

package school.student2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import school.student.Student;

public class App {
    public static void main(String[] args) {
        //1. 得到 Spring 的上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-test.xml");
        //2. 调用 getBean() 方法获取指定的 Bean 对象
        StuController stuController = context.getBean("stuController", StuController.class);
        //3. 使用bean 对象
        Student student = stuController.getStu("1");
        System.out.println(student.toString());
    }
}

 属性注入的核心:


3.2 构造方法注入

构造方法注入是在类的构造方法中实现注入:同样使用 @Autowired 注解

 如果只有一个构造方法,那么 @Autowired 注解可以省略不写:

如果类中出现多个构造方法,那么需要添加上 @Autowired 来明确指定到底使用哪个构造方法,否则程序会报错。


3.3 Setter 注入

Setter 本质上就是使用自定义方法来代替构造方法注入,也是需要在 set 方法上添加 @Autowired 注解:

注意:使用 Setter 注入一定要添加@Autowired 注解


3.4 三种注入优缺点分析

3.4.1 属性注入

优点:实现起来比较简单,只需要一个@Autowired 注解

缺点:

1. 不能注入不可变的(final)的对象

final 修饰的引用,只能在创建的时候进行初始化赋值操作,或在构造方法中初始化。

 2. 只能适用于 loC 容器

属性注入通常与IoC(控制反转)容器紧密相关,并且在大多数情况下,它更常用于IoC容器中。IoC容器通过管理对象的生命周期、依赖关系和对象创建等任务,将控制权交给框架,以实现解耦和可扩展性。总体而言,属性注入与IoC容器密切相关,并且在通过IoC容器管理对象时,属性注入是一种常用的依赖注入方式,能够帮助实现代码的解耦和可配置性。然而,在非IoC场景下,属性注入的使用可能会受到一些限制,并且可能不如其他依赖注入方式适用。

3. 更容易违背单一设计原则(针对类)

属性注入在某些情况下可能会违背单一设计原则(Single Responsibility Principle,SRP)。SRP的目标是确保一个类对于变化的原因只有一个,以便提高代码的可维护性和灵活性。它强调职责的划分和分离,使每个类专注于单一的功能或关注点

以下是属性注入可能导致违背SRP的一些情况:

  1. 依赖过多:属性注入可能导致一个类具有过多的依赖关系。如果一个类依赖过多的其他类或组件,那么它可能承担过多的职责。这样的类可能会变得庞大而难以理解和维护。

  2. 责任扩散:属性注入可能导致一个类承担不应该由它承担的额外职责。当一个类注入了许多属性时,特别是来自不同领域的属性,它可能参与多个责任和业务逻辑,从而违反SRP。

  3. 耦合度增加:属性注入可能导致类之间的耦合度增加。如果一个类对其依赖项的实例化和配置有太多控制权,它与这些依赖项之间的耦合度会增加。这使得类的扩展和修改变得更加困难。

虽然属性注入在一些情况下可能会违背SRP,但这并不意味着属性注入本身是错误的或应该完全避免的。合理使用属性注入,可以通过分割类的职责、解耦依赖关系和保持代码的可维护性来避免违背SRP。在设计和实现过程中,应该谨慎选择注入的属性和依赖项,确保它们与类的职责和关注点保持一致,避免过度复杂化和耦合。


3.4.2 构造方法注入

优点:

1. 可以注入一个不可变(final修饰)对象,构造方法可以为其赋值。

 2. 注入的对象不会被修改

  • 可以被 final 的修饰(只有一个实例)
  • 构造方法伴随着类加载只执行一次

3. 通用性更好

通过构造方法注入,类的依赖关系可以明确地表达出来,构造方法注入允许依赖关系在类的实例化阶段就被传递进来。这意味着在类的实例化过程中,可以清楚地看到类所依赖的对象是哪些,而不是在方法调用时才进行依赖注入。

缺点:

没有属性注入实现简单。

需要注意的是,构造方法注入并不适用于所有情况,特别是当所依赖的对象较多时,会出现构造方法参数列表冗长的问题。在这种情况下,可以考虑使用其他形式的依赖注入方式,如属性注入或方法注入,来提供更灵活的注入方式。选择合适的依赖注入方式,取决于具体的情况和项目需求。

构造方法注入是 Spring 官方推荐的注入方法。


3.4.3 Setter 方式注入(普通方法注入)

Setter 方法是 Spring 早期版本推荐的注入方式,。

优点:比较符合单一设计原则(SRP),方法嘛,针对的是方法级别的,虽然在通用性上没有构造方法强,Setter方法注入也有其适用的场景,比如可选的依赖项或动态变化的依赖关系。在这些情况下,setter方法注入可能更为灵活和方便。选择合适的依赖注入方式,需要根据具体需求和设计原则进行权衡和判断。

缺点:

1. 不能注入不可变(final)的对象;

final 修饰的引用,只能在创建的时候进行初始化赋值操作,或在构造方法中初始化。

2. 注入对象可以被修改

set 方法是普通的方法,可以被重复调用,在调用时就存在被修改的风险。Spring 现版本已经推荐使用构造方法注入的方式来进行类注入。


3.5 @Resource 注入

在 Java 里面在进行类注入时,除了使用 @Autowired 注解,还可以使用 @Resource 注解:

 @Autowired 和 @Resource 都是在 Java 中用于进行依赖注入的注解,但它们有一些不同之处。


3.5.1 @Autowired 和 @Resource 的区别

  1. 出生不同:@Autowired 注解出自于Spring框架(非官方),  @Resource 注解出自于 JDK(官方)。
  2. 功能支持不同:@Autowired 可用于属性注入,构造方法注入,和 Setter(普通方法) 注入.而 @Resoure 只能用于 Setter 注入和属性注入, 不能用于构造方法注入(意味着不能注入不可变对象).
  3. 参数支持不同:  @Resource 支持更多的参数设置, 例如: 对Bean 取一个名字(name), 而 @Autowired 只能设置 required 参数。required 是 @Autowired 注解的一个可选属性,默认值为 true。它用于指定依赖注入是否是必需的。当 required 属性设置为 true 时,如果找不到匹配的依赖对象,则会抛出 NoSuchBeanDefinitionException 异常。

示例:

@Autowired(required = true)
private MyDependency myDependency;

当 required 属性设置为 false 时,如果找不到匹配的依赖对象,则会将依赖对象设置为 null,即允许依赖注入的可选性。

示例:

@Autowired(required = false)
private MyDependency myDependency;

尽管 required 默认值为 true,但是在某些情况下,我们可能使用 @Autowired(required = false) 来标记可选的依赖注入,以便在没有匹配的依赖对象时不抛出异常。这在需要可选依赖或动态注入的场景下非常有用。


3.6 @Bean 注入多个同类型的 bean 对象报错处理

当我们使用 @Bean 方法注解往 Spring 中注入多个同类型的 Bean 对象时,就会报错。

注意:以往的例子我们需要在 Spring 配置文件中将路径注释一下,不然启动的时候Spring 容器中会注册多个同类型的 bean对象(stu)。

@Component
public class StudentDemo {
    StudentDemo() {
        System.out.println("StudentDemo 执行");
    }
    @Bean
    public Student getStu() {
        //1. 创建对象
        Student student = new Student();
        //2. 初始化对象
        student.setId("1");
        student.setName("李小四");
        student.setSex("男");
        student.setAge(18);
        //3. 返回对象
        return student;
    }

    @Bean
    public Student getStu2() {
        //1. 创建对象
        Student student = new Student();
        //2. 初始化对象
        student.setId("2");
        student.setName("王小五");
        student.setSex("男");
        student.setAge(20);
        //3. 返回对象
        return student;
    }
}

在另一个类中获取 Student 对象:

public class StudentApp {
    public static void main(String[] args) {
        //1. 得到 Spring 的上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-test.xml");
        //2. 调用 getBean() 方法获取指定的 Bean 对象
        StudentController stuController = context.getBean(StudentController.class);

        //3. 利用 stuController 对象的 getStudent()获取 bean 对象
        Student student = stuController.getStudent();
        System.out.println(student.toString());
    }
}

@Controller
class StudentController {

    //1. 注入 student 对象,在StudentDemo 类中我们使用 @Bean 注入了两个stu 对象
    @Autowired
    private Student student;

    //2. 返回
    public Student getStudent() {
        return student;
    }
}

以上程序执行结果:

同一类型多个 Bean 报错处理: 

  • 使用Resoure(name = "FunctionName") 进行类注入的时候只能指定获取@Bean注解修饰方法的名字,如此一来,问题迎刃而解~
  • 使用@Qualifier 注解定义名称,可以跟@Autowired 注解配合使用(Autowired 注解不可以指定name 注入)。

1. 使用 @Resource(name = "XXXXX") 定义

2. 使用 @Qualifier 

@Qualifier注解 用于帮助指定特定的依赖注入或自动装配。它通常与依赖注入框架(如Spring)一起使用,以解决多个候选对象的歧义性。在依赖注入中,当存在多个相同类型的bean时,可以使用@Qualifier注解来标识要使用的具体bean。通过在@Qualifier注解中指定一个唯一的标识符(name),可以告诉依赖注入框架,注入哪个具体的bean。


 四、总结

1. 将对象存储到 Spring 中:

  • 古老一点的做法是在 Spring 配置文件的 <Beans> </Beans> 标签下直接添加注解。

不好的一点是比较麻烦,每个 Bean 对象都需要我们手动的添加,对此我们有了注解的方式。

  • 使用类注解:@Controller 、@Service、@Repository、@Configuration、@Component这些其他注解的内部都有一个 @Component注解, 说明这些注解可以认为是 @Component 的子类.

使用类注解:需要在Spring 配置文件中设置包扫描路径,当Spring 启动时,会根据包路径下的类注解将修饰的类实例到 Spring 当中,类直接需要配合扫描路径使用,不然无法成功注入(此处是单例模式,一个类只有一份实例)。

  • 使用方法注解 @Bean 【注意事项:必须配合类注解一起使用】

2. Bean 对象的命名规则

类首字母大写和类首字母小写及第二个字母小写,都是默认都是通过首字母小写作为name 来获取 Bean ;如果类首字母和第二个字母都是大写,那么直接使用原类名作为name 来获取 Bean 。

3. 从Spring 中获取bean 对象:

  • 属性注入 
  • 构造方法注入(官方推荐)
  • Setter 注入

 4. 注入的关键字:

@Autowired 和 @Resource

5. @Autowired 与 @Resource 的区别:

  • 出生不同:Autowired 出自Spring  ,Resource 出自 JDK
  • 参数不同:@Resource 支持更多的参数,例如可以在获取的时候给 Bean 对象取名字
  • 功能的不同:@Autowired 支持属性注入,构造方法注入和 Setter 方法注入,@Resource 只支持属性注入和 Setter 方法注入。

6. 解决@Bean 方法注解注入多个同类型 Bean 对象的报错:

  • 使用 @Resource(name= " 方法名")
  • 使用 @Qualifier (value = "方法名")

人生的旅途中,前面还有无数个日子需要别无选择地去面对。

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

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

相关文章

【Unity面试篇】Unity 面试题总结甄选 |Unity进阶篇 | ❤️持续更新❤️

前言 关于Unity面试题相关的所有知识点&#xff1a;&#x1f431;‍&#x1f3cd;2023年Unity面试题大全&#xff0c;共十万字面试题总结【收藏一篇足够面试&#xff0c;持续更新】为了方便大家可以重点复习某个模块&#xff0c;所以将各方面的知识点进行了拆分并更新整理了新…

总结926

总结&#xff1a;今晚状态极佳&#xff0c;回去路上差点被宿管阿姨锁在楼下。之前每每学到晚上脑子都转不动了&#xff0c;不过今晚就像是适应了一样。这也说明&#xff0c;学习&#xff0c;是可以上瘾的。只要循序渐进&#xff0c;步步为营&#xff0c;就不断收获学习的乐趣。…

解决uniapp运行手机基座出现的问题

常见的问题&#xff1a;&#xff08;往往在更新编辑器版本后会出现以下问题&#xff09; 问题1.明明已经连接到手机&#xff0c;就是检测不到设备 问题2.同步资源失败&#xff0c;未得到同步资源的授权 解决办法汇总 问题1解决办法&#xff1a; 方法一&#xff1a;进入HBuild…

关系型数据库范式

范式 前置知识第一范式&#xff08;1NF&#xff09;第二范式&#xff08;2NF&#xff09;第三范式&#xff08;3NF&#xff09;BC范式&#xff08;BCNF&#xff09;第四范式&#xff08;4NF&#xff09;范式化设计和反范式化设计的优缺点&#xff1f; 前置知识 超键(super key)…

mq延时队列使用

一、基本配置 导入依赖 <!--高级消息队列协议amqp--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>application.yml配置 #rabbitmqrabbitmq:host: 192…

02 半同步半反应堆线程池

服务器编程基本框架 主要由I/O单元&#xff0c;逻辑单元和网络存储单元组成&#xff0c;其中每个单元之间通过请求队列进行通信&#xff0c;从而协同完成任务。 其中I/O单元用于处理客户端连接&#xff0c;读写网络数据&#xff1b;逻辑单元用于处理业务逻辑的线程&#xff1b…

ES7~ES13新特性(二)

1 ES7新增特性解析 2 ES8新增特性解析 3 ES10新增特性解析 4 ES11新增特性解析 5 ES12新增特性解析 6 ES13新增特性解析 ES8-对象相关的属性 ---entries的使用 const obj {name: "why",age: 18,height: 1.88,address: "广州市"}// 1.获取所有的keyco…

【NLP】Transformer模型原理(2)

接上文 【NLP】Transformer模型原理(1) 六、零层的transformer 观看涵盖与本节类似内容的视频:0 层理论 在进入更复杂的模型之前,简要考虑一下“零层”变压器很有用。这样的模型获取一个令牌,嵌入它,解嵌它以生成预测下一个令牌的对数: ​

音频数据分割单独处理后再拼接出现跳跃间断点的处理方法

+hezkz17进数字音频系统研究开发交流答疑 1如图所示 问题1: 对于一个81920字节的音频文件,如果是分割成小块4096输入(无重叠,均分),在频域上做去噪算法,每4k数据返回到时域上再拼接成80k的处理结果文件,发现处理结果有异常有跳跃间断点,像是频谱泄露?分割也需要有重…

mysql函数练习

创建表sch 向表中加入数据 1、创建一个可以统计表格内记录条数的存储函数 &#xff0c;函数名为count_sch() CREATE DEFINERroot% FUNCTION count_sch() RETURNS int(11) BEGINDECLARE total INT DEFAULT 0;#Routine body goes here...SELECT count(1) into total from sch;IN…

Linux->初识计算机网络

目录 前言&#xff1a; 1 网络发展背景 2 协议 2.1 网络协议初识 2.2 协议分层 2.3 OSI、TCP/IP层状模型 2.4 协议和操作系统的关系 2.5 根据协议栈的通信 3 网络中的地址管理 前言&#xff1a; 本篇当中没有任何关于网络编程的讲解&#xff0c;全部是对网络的宏观理解…

Go语言github.com/gorilla/websocket框架websocket协议通信实战

websocket是实际开发中比较常用的应用层协议&#xff0c;本文利用github.com/gorilla/websocket框架进行websocket通信实战。 目录 1.下载github.com/gorilla/websocket 2.websocket服务端 3.websocket Go客户端 4.websocket 网页客户端 5.运行结果展示 1.下载github.com…

【UI自动化测试】appium+python+unittest+HTMLRunner

进阶Python接口自动化测试必备教程&#xff08;2023全网最详细&#xff09; 简介 获取AppPackage和AppActivity 定位UI控件的工具 脚本结构 PageObject分层管理 HTMLTestRunner生成测试报告 启动appium server服务 以python文件模式执行脚本生成测试报告 下载与安装 下载需要自…

深度学习(28)——YOLO系列(7)

深度学习&#xff08;28&#xff09;——YOLO系列&#xff08;7&#xff09; 咱就是说&#xff0c;需要源码请造访&#xff1a;Jane的GitHub&#xff1a;在这里 上午没写完的&#xff0c;下午继续&#xff0c;是一个小尾巴。其实上午把训练的关键部分和数据的关键部分都写完了…

macOS 怎么安装redis数据库

1 访问redis数据库下载网址 http://download.redis.io/releases/ 访问上述的redis下载的网址&#xff0c;确定你想要的版本 然后下载即可 &#xff08;我选则的是6.2.6&#xff09; 然后下载 下载后 把这个文件解压&#xff0c;放在自己想要放在的位置 2 打开终端 输入对应的…

Hadoop 单机部署和测试(一)

Hadoop单机部署和测试 一.单机部署1.安装 JDK&#xff08;JDK11&#xff09;2.安装 HADOOP3.测试 一.单机部署 系统版本&#xff1a;cat /etc/anolis-release1.安装 JDK&#xff08;JDK11&#xff09; #!/bin/bashTOP_PATH$(pwd) JAVA_PATH/usr/local/java FILEls $TOP_PATH/…

本地部署 Stable Diffusion XL Gradio Demo WebUI

StableDiffusion XL Gradio Demo WebUI 0. 先展示几张 StableDiffusion XL 生成的图片1. 什么是 Stable Diffusion XL Gradio Demo WebUI2. Github 地址3. 安装 Miniconda34. 创建虚拟环境5. 安装 Stable Diffusion XL Gradio Demo WebUI6. 启动 Stable Diffusion XL Gradio De…

【LeetCode周赛】2022上半年题目精选集——动态规划

文章目录 2140. 解决智力问题解法1——倒序DP&#xff08;填表法&#xff09;解法2——正序DP&#xff08;刷表法&#xff09;⭐⭐⭐ 2167. 移除所有载有违禁货物车厢所需的最少时间⭐⭐⭐解法1——前缀和⭐⭐⭐⭐⭐解法2——前后缀分解 动态规划代码1——看了思路之后自己写的…

java中json和对象之间相互转换的运用

1.目录结构 2.配置相关文件 2.1.引入相关的pom文件 pom.xml <dependencies><!-- JSON --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.3</vers…

linux 基于debian_ubuntu AB系统适配(三)- overlayroot

Overlayroot Overlayroot是一个实用工具,允许您创建一个只读的根文件系统和一个可写的覆盖文件系统。这对于创建一个更安全和稳定的系统很有用,因为对系统所做的任何更改都将存储在覆盖文件系统中,可以很容易地丢弃或重置。 在Debian下,分离的系统在/userdata/rootfs_ove…