Spring依赖注入、对象装配

news2024/11/23 15:05:21

文章目录

  • 依赖注入与对象装配
  • 依赖注入的常见方式
    • 属性注入(Property Injection)
      • 属性注入的优缺点
    • Setter 注入(Setter Injection)
      • Setter注入优缺点
    • 构造函数注入(Constructor Injection)
      • 构造函数注入优缺点
    • 依赖注入推荐用法
  • @Resource:另一种注入关键字
  • 同⼀类型多个 @Bean 报错
    • 使⽤ @Resource(name="user1") 解决
    • 使用 @Qualifier 注解解决
  • 什么是单一设计原则
  • 总结

依赖注入与对象装配

依赖注入(Dependency Injection) 是Spring框架的一大特色。咱们可以把它想象成是一种“自动传递东西”的方式,就像你坐电梯不需要自己操作按钮,电梯会帮你到达目的地一样。在程序中,当一个类需要用到另一个类的功能时,不需要自己去创建,而是由Spring自动帮你注入所需的对象。这样做有点像你在做披萨,需要的配料自己不用操心,厨师会给你加好。

对象装配(Object Assembly) 则是Spring中的一个步骤,就像你把积木拼在一起一样。它是通过配置文件或者注解来告诉Spring如何把不同的类组合在一起,形成一个完整的程序。就像你组装一辆汽车,需要把引擎、轮子、座位等组件组合在一起,Spring帮你把各个类组装成一个强大的系统。

首先,我们需要创建一些类,就像你在搭积木,每个类都有自己的功能。然后,在Spring的配置中,你会告诉Spring这些类之间的关系,以及谁需要谁的功能。Spring会在需要的时候,自动把这些类创建并组装起来,就像你玩乐高积木,把各种小块搭建成一个酷炫的模型。

举个例子吧!假设你要开发一个图书管理系统。你有一个 Book 类表示图书,还有一个 Library 类表示图书馆。在Spring中,你可以通过依赖注入,让图书馆知道它需要用到图书,然后Spring会自动给它注入图书的实例。就像你在图书馆借书,不需要自己找,图书管理员会把书递给你一样。

配置这些关系可以通过XML配置文件,也可以使用注解。你可以告诉Spring哪些类需要注入,哪些属性需要赋值,就像你在指挥乐团,把每个乐器的音符安排得和谐动听。

Spring的依赖注入和对象装配让你的代码更加整洁、灵活,让你可以更专注于解决实际问题,而不用纠结于类与类之间的繁琐连接。

依赖注入的常见方式

Spring提供了多种方法来帮助你将不同的类连接在一起,实现依赖注入。以下是一些常见的依赖注入方式:

属性注入(Property Injection)

属性注入是我们最熟悉,也是日常开发中使用最多的一种注入方式。通过类的属性来注入依赖。这通常需要提供一个设置方法(setter)来设置依赖。就像你在乐高积木上插入一个小块一样,将依赖的类通过属性赋值进来。

@Controller
public class UserController {
    // 从 spring 容器中获取 UserService 对象
    /**
     * 1.属性注入@Autowired  自动装配
     */
    @Autowired
    private UserService userService;

    public void sayHello() {
        System.out.println("Hello ");
        userService.doService();
    }
}

这里的UserService对象就像属性一样直接能被UserController调用,所有叫属性注入。

属性注入的优缺点

优点

属性注入最大的优点就是实现简单、使用简单,只需要给变量上添加一个注解(@Autowired),直接获得注入的对象了,所以它的优点就是使用简单。

缺点

  1. 功能缺陷: 不能注入一个final修饰的属性,在JavaSE中final修饰的变量要么使用时直接赋值,要么构造方法赋值,在这里两者都不满足,所以报错。
    在这里插入图片描述
  2. 通用性问题: 只适用于IoC容器。,如果将属性注入的代码移植到其他非 IoC 的框架中,那么代码就无效了,所以属性注入的通用性不是很好。
  3. 设计原则问题: 使用属性注入的方式,因为使用起来很简单,所以开发者很容易在一个类中同时注入多个对象,而这些对象的注入是否有必要?是否符合程序设计中的单一职责原则?就变成了一个问题。但可以肯定的是,注入实现越简单,那么滥用它的概率也越大,所以出现违背单一职责原则的概率也越大
    注意:这里强调的是违背设计原则(单一职责)的可能性,而不是一定会违背设计原则,二者有着本质的区别。

Setter 注入(Setter Injection)

Setter 注入 是通过设置方法(setter)来实现依赖注入的方式。这种方法允许你在类中定义一个或多个设置方法,用于注入依赖对象。

/**
 * 2.setter注入
 */
private UserService userService;

@Autowired
public void setUserService(UserService userService) {
    this.userService = userService;
}

public void sayHello() {
    System.out.println("Hello ");
    userService.doService();
}

Setter注入优缺点

优点

完全符合单一职责的设计原则,每一个 Setter 只针对一个对象

缺点

  1. 不能注入不可变对象
    使用 Setter 注入依然不能注入不可变对象,比如以下注入会报错:
    在这里插入图片描述
  2. 注入对象可被修改
    Setter 注入提供了 setXXX 的方法,意味着你可以在任何时候、在任何地方,通过调用 setXXX 的方法来改变注入对象,所以 Setter 注入的问题是,被注入的对象可能随时被修改。

构造函数注入(Constructor Injection)

通过构造函数,你可以在创建一个类的实例时传入它所依赖的其他类的实例。就像你在组装一个模型,每个积木块都是构造函数的一个参数,将它们组合在一起就形成了完整的模型。

/**
 * 3.构造器注入
 */
private UserService userService;

@Autowired
public UserController(UserService userService) {
    this.userService = userService;
}

public void sayHello() {
    System.out.println("Hello ");
    userService.doService();
}
  • 如果当前的类中只有一个构造方法,那么 @Autowired 可以省略

构造函数注入优缺点

优点

构造方法注入相比于前两种注入方法,它可以注入不可变对象,并且它只会执行一次,也不存在像 Setter 注入那样,被注入的对象随时被修改的情况,它的优点有以下 4 个:

  1. 注入不可变对象
    使用构造方法注入可以注入不可变对象,并不会报错
    在这里插入图片描述
  2. 注入对象不会被修改
    构造方法注入不会像 Setter 注入那样,构造方法在对象创建时只会执行一次,因此它不存在注入对象被随时(调用)修改的情况。
  3. 完全初始化
    因为依赖对象是在构造方法中执行的,而构造方法是在对象创建之初执行的,因此被注入的对象在使用之前,会被完全初始化,这也是构造方法注入的优点之一。
  4. 通用性更好
    构造方法和属性注入不同,构造方法注入可适用于任何环境,无论是 IoC 框架还是非 IoC 框架,构造方法注入的代码都是通用的,所以它的通用性更好。

缺点

构造函数可以有多个参数,当有多个参数时,不符合单一设计原则。

依赖注入推荐用法

Spring 4.2 之前推荐的注入用法是 Setter,Spring 4.2 之后推荐使用构造方法注入

@Resource:另一种注入关键字

在进⾏类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊。

  • 实现属性注入
  • 实现setter注入
  • 不能用于构造函数注入

与@Autowired的区别

  • @Autowired 来⾃于 Spring,⽽ @Resource 来⾃于 JDK 的注解
  • 相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如 name 设置,根据名称获取 Bean

同⼀类型多个 @Bean 报错

当出现以下多个 Bean,返回同⼀对象类型时程序会报错,如下:

@Component
public class Users {

    @Bean
    public User user1() {
        User user = new User();
        user.setName("fyd");
        user.setAge(18);
        return user;
    }

    @Bean
    public User user2() {
        User user = new User();
        user.setName("fyd2");
        user.setAge(19);
        return user;
    }
}

获取User对象,如下:

@Controller
public class UserController {

    @Resource
    private User user;

    public User getUser() {
        return user;
    }
}

程序报错如下:
没有 "com.fyd.User "类型的符合条件的 Bean:预期只有一个匹配的 Bean,但发现了 2 个:user1,user2
在这里插入图片描述
这里我们有两个一样类型的Bean对象,所以我们直接注入程序分不清是要注入哪一个。

使⽤ @Resource(name=“user1”) 解决

在这里插入图片描述

使用 @Qualifier 注解解决

在这里插入图片描述

什么是单一设计原则

当谈论软件设计时,“单一设计原则”(Single Responsibility Principle,简称 SRP)是面向对象编程中的一个重要原则之一。它强调一个类应该只有一个引起它变化的原因,也就是说,一个类应该只负责一项职责。

这个原则的核心思想是,将一个类的功能限制在一个明确的范围内,使得该类的修改只会因为这个范围内的需求变化,而不会受到其他无关功能的影响。这有助于代码的可维护性、可读性和可扩展性,因为当一个类只关注一项职责时,它的代码更加清晰,容易理解和修改。

举个例子来解释单一设计原则:假设你正在开发一个图书馆管理系统,你可能会有一个 Book 类负责表示图书的信息,另一个 Library 类负责管理图书的借阅和归还。按照单一设计原则,Book 类只需要关注图书本身的属性和方法,而 Library 类只需要关注图书的管理,这样两个类的职责得到了明确的划分。

然而,当一个类承担了过多的职责时,代码可能变得混乱,难以维护。如果在上述例子中,你让 Book 类既负责图书信息又负责图书管理,那么当图书信息或图书管理的需求变化时,就可能需要同时修改 Book 类的多个部分,增加了代码变更的风险和复杂性。

单一设计原则的目标是使每个类都变得更加聚焦和专注,减少类之间的耦合,提高代码的可维护性和灵活性。通过将不同的职责分开,你可以更容易地修改、测试和扩展每个类,从而更好地满足软件的需求。

总结

在这篇博客中,我们学习到了spring依赖注入的三种常见的方式,并且了解了它们的优缺点,还了解了依赖注入的两个重要的关键字:@Autowired、@Resource,并了解了两者的区别。还知道了如何解决同一类型Bean注入的报错问题和了解了软件设计中的单一设计原则。

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

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

相关文章

Unity游戏源码分享-多角色fps射击游戏

Unity游戏源码分享-多角色fps射击游戏 项目地址:https://download.csdn.net/download/Highning0007/88204023

Flutter BottomSheet 三段式拖拽

BottomSheetBehavior 追踪 BottomSheet系统默认实现效果准备要实现的功能点:定义三段式状态:BottomSheetBehavoir阀值定义1. 未达到滚动阀值,恢复状态2. 达到滚动阀值,更新状态 前面倒是有讲过Android原生的BottomSheetBehavior&a…

Camunda 7.x 系列【2】开源工作流引擎框架

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 2.7.9 本系列Camunda 版本 7.19.0 源码地址:https://gitee.com/pearl-organization/camunda-study-demo 文章目录 1. 前言2. 开源工作流引擎框架2.1 jBPM2.2 Activ…

综合技巧练习 - Packet Tracer 简介

1.7.1:综合技巧练习 - Packet Tracer 简介 拓扑图: 以基本完成的逻辑拓扑为起点。 设备 接口 IP 地址 子网掩码 默认网关 R1-ISP Fa0/0 192.168.254.253 255.255.255.0 不适用 S0/0/0 10.10.10.6 255.255.255.252 R2-Central Fa0/0 17…

DTC服务(0x14 0x19 0x85)

DTC相关的服务有ReadDTCInformation (19) service,ControlDTCSetting (85) service和ReadDTCInformation (19) service ReadDTCInformation (19) service 该服务允许客户端从车辆内任意一台服务器或一组服务器中读取驻留在服务器中的诊断故障代码( DTC )信息的状态…

并发——ThreadPoolExecutor 类简单介绍

文章目录 1 ThreadPoolExecutor 类分析2 推荐使用 ThreadPoolExecutor 构造函数创建线程池 线程池实现类 ThreadPoolExecutor 是 Executor 框架最核心的类。 1 ThreadPoolExecutor 类分析 ThreadPoolExecutor 类中提供的四个构造方法。我们来看最长的那个,其余三个…

P15 电路定理——巧妙-灵性-智慧

1、戴维南定理 2、戴维南定理的证明 对于线性含源的一个结构, 右边接一个支路N,再用电流源替代N 情况一:A没有独立源,那么A可以等价于一个电阻 情况二:A有独立源,例证法: 使用叠加法&#xf…

获取 Android 的 SHA1 值

1、调试版,可以直接在 Android studio 中的 gradle 中查看。也可以用下面方法进行 前提要先确定签名文件所在的路径:调试版默认使用的签名文件是debug.keystore,文件处于 C 盘用户目录下的.android文件夹下。打开命令行工具, 1、…

分析为何科研转化率低

最近这两天,[广西审计:高校1.31亿科研经费成果转化率为0] 话题引发热议。据报道,广西壮族自治区审计厅近日公布的《关于2022年度自治区本级预算执行和其他财政收支的审计工作报告》披露了广西在科教振兴资金审计方面 9 所高校开展科研的相关情况。报告发…

Flutter:文件上传与下载(下载后预览)

Dio dio是一个强大的Dart Http请求库,提供了丰富的功能和易于使用的API,支持文件上传和下载。 这个就不介绍了,网上有很多的封装案例。 background_downloader 简介 适用于iOS,Android,MacOS,Windows和L…

使用 prometheus client SDK 暴露指标

目录 1. 使用 prometheus client SDK 暴露指标1.1. How Go exposition works1.2. Adding your own metrics1.3. Other Go client features 2. Golang Application monitoring using Prometheus2.1. Metrics and Labels2.2. Metrics Types2.2.1. Counters:2.2.2. Gauges:2.2.3. …

【ECharts】树图

将3级改成4级 demo上是3层,如何实现4层。 initialTreeDepth: 4

【hello C++】特殊类设计

目录 一、设计一个类,不能被拷贝 二、设计一个类,只能在堆上创建对象 三、设计一个类,只能在栈上创建对象 四、请设计一个类,不能被继承 五、请设计一个类,只能创建一个对象(单例模式) C🌷 一、设计一个类&…

zynq复位管脚的方式

问:实际应用中,是不是PS_SRST_B必须,但是POR不是必须? 答:POR是必须有的,不然只能掉电复位,POR都是画上的。POR是整个芯片最高级复位,就是整个芯片都会复位。PS支持外部上电复位信号…

数据库新闻速递 -- POSTGRESQL 正在蚕食数据库市场 (翻译)

开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请加 liuaustin3微信号 ,在新加的朋友会分到3群&#xff…

什么是DNS服务器的层次化和分布式?

DNS (Domain Name System) 的结构是层次化的,意味着它是由多个级别的服务器组成,每个级别负责不同的部分。以下是 DNS 结构的层次: 根域服务器(Root Servers): 这是 DNS 层次结构的最高级别。全球有13组根域…

开发命名规范

1项目命名规范 1、工程项目名,尽量想一些有意义、有传播价值的名称;比如星球、游戏、名人、名地名等;取名就跟给孩子取名一样,独特、有价值、有意义、好传播 2、所有的类都必须添加创建者和创建日期 3、所有代码:包括…

vteamled透明屏,在商业领域中的显示效果怎么样?高清、亮度

vteamled透明屏是一种新型的显示屏技术,它采用透明材料制成,可以实现透明显示效果。vteamled透明屏具有以下特点: 首先,vteamled透明屏具有高透明度。 它采用高透明材料制成,可以达到80%以上的透明度,使得…

Laravel 框架数据库配置构造器的查询.分块.聚合 ⑤

作者 : SYFStrive 博客首页 : HomePage 📜: THINK PHP 📌:个人社区(欢迎大佬们加入) 👉:社区链接🔗 📌:觉得文章不错可以点点关注 &#x1f44…

激活函数总结(四):Hard系列激活函数补充(HardSigmoid、HardTanh、Hardswish)

激活函数总结(四):Hard系列激活函数补充 1 引言2 激活函数2.1 HardSigmoid激活函数2.2 HardTanh激活函数2.3 Hardswish激活函数 3. 总结 1 引言 在前面的文章中已经介绍了过去大家较为常见的激活函数 (Sigmoid、Tanh、ReLU、Leaky ReLU、PRe…