2023.11.7 Spring 依赖注入的三大方式

news2024/12/27 13:39:31

目录

前言

属性注入(@Autowired)

Setter 注入

构造方法注入

 @Resource

@Autowired 和 @Resource 的区别

@Autowired 和 @Resource 查找 Bean 对象的区别


前言

配置文件

​
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--base-package 表示要扫描的路径-->
    <content:component-scan base-package="com.java.demo"></content:component-scan>
</beans>

​

启动类

import com.java.demo.controller.StudentController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
//        得到 Spring 上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//        获取 Bean 对象
        StudentController studentController  = context.getBean("studentController",StudentController.class);
        studentController.sayHi();
    }
}
  • 在启动类中,不能使用下述三种注入方式来实现对象的注入
  • 运行启动类时,需要执行 main 方法,然而 main 方法被 static 关键字所修饰的,即 main 方法为静态方法
  • 静态方法的加载顺序是高于 Spring 容器初始化的
  • 所以在该静态方法中,我们无法使用以下三种依赖注入的方式来获取 Bean 对象
  • 所以在下文 举例实现这三种依赖注入的方式 时,我们还是会通过 启动类 来获取 StudentController 的 Bean 对象
  • 但是会在 StudentController 类中使用以下三种依赖注入的方式,来实现在StudentController 类中成功注入 UserService 类的 Bean 对象

属性注入(@Autowired)

  • 日常开发中,属性注入是我们最常用的一种注入方式

实例

import com.java.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

// 使用 @Controller 注解将当前类存储到 spring 容器中
@Controller
public class StudentController {

    @Autowired // 注入 UserService 的 Bean 对象
    private UserService userService;

    public void sayHi() {
        System.out.println("student controller say hi");
//        直接调用执行 userService 的成员方法
        userService.sayHi();
    }
}

运行启动类的结果:


重点理解

使用属性注入时:

  • 首先 ApplicationContext 在 Spring 容器启动时就会被实例化和初始化,并它会在启动过程中创建和管理所有的 Bean 对象
  • 随后容器在创建 StudentController 类的 Bean 对象时,会自动检测 StudentController 类的依赖关系并注入相应的依赖对象
  •  UserService 的 Bean 对象,便在此时由 Spring 容器自动注入给了 StudentController 类
  • 即 StudentController 类中的 userService 对象被 Spring 容器直接赋值

优点

  • 实现简单、使用简单
  • 只需给变量上添加一个注解(@Autowired),即可获得注入的 Bean 对象

缺点

1、无法实现 final 修饰的变量注入

  • 在 Java 中被 final 关键字修饰的变量被称为常量
  • 常量的声明和初始化需要在同一时间完成,且只能被赋值一次
  • 方式一:直接赋值
  • 方式二:通过构造方法赋值

2、只适用于 IoC 容器(兼容问题)

  • 如果将属性注入的代码移植到其他非 IoC 的框架中,该代码就无效了,所以其兼容性有限

3、因为写法简单,所以违背单一职责原则的概率更大(存在风险)

  • 单一职责原则 是面向对象设计中的一个重要原则,它指出一个类应该有且只有一个引起它变化的原因
  • 此处强调的是违背单一职责原则的可能性,而不是一定会违背单一职责原则,这与程序员自己的代码强相关

Setter 注入

实例

import com.java.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

// 使用 @Controller 注解将当前类存储到 spring 容器中
@Controller
public class StudentController {

    //    使用 Setter 注入
    private UserService userService;

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

    public void sayHi() {
        System.out.println("student controller say hi");
//        直接调用执行 userService 的成员方法
        userService.sayHi();
    }
}
  • 此处需要使用 @Autowired 添加到 Setter 方法上
  • 代表着 Spring 会针对该 Setter 方法 的参数进行相应的赋值

运行启动类执行结果:


重点理解

使用 Setter 注入时:

  • 首先 ApplicationContext 在 Spring 容器启动时就会被实例化和初始化,并它会在启动过程中创建和管理所有的 Bean 对象
  • 随后容器在创建 StudentController 类的 Bean 对象时,会自动检测 StudentController 类的依赖关系并注入相应的依赖对象
  •  UserService 的 Bean 对象,便在此时由 Spring 容器自动注入给了 StudentController 类
  • 即 StudentController 类中的 setUserService 方法的参数直接被 Spring 容器给赋值
  • 然后通过方法中的 this.userService = userService 语句
  • 将被 Spring 容器赋值的 userService 对象,传递赋值给 StudentController 类中userService 变量
  • 此刻 StudentController 类便可以成功使用 UserService 类的 Bean 对象了

缺点

1、同样无法实现 final 修饰的变量注入

2、注入对象可被修改

import com.java.demo.controller.StudentController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
//        得到 Spring 上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//        获取 Bean 对象
        StudentController studentController  = context.getBean("studentController",StudentController.class);
//        setUserService 可以被随便调用,然后改变原先已经被 Spring 容器注入好的 userService Bean 对象
//        此处直接将 studentController 对象中的 userService 变量的值改为 null
        studentController.setUserService(null);
//        执行到此处时便会发生报错
        studentController.sayHi();
    }
}

运行结果:

图解原因:

构造方法注入

  • 构造方法注入是 Spring 官方推荐的注入方式
  • 但是日常开发用的最多的还是属性注入

特点:

  • 如果当前类中只有一个构造方法的话, @Autowired 注解可以省略

实例

import com.java.demo.service.UserService;
import org.springframework.stereotype.Controller;

// 使用 @Controller 注解将当前类存储到 spring 容器中
@Controller
public class StudentController {

    //    使用 构造方法 注入不可变对象
    private final UserService userService;

//    @Autowired  因为当前类仅一个构造方法,所以此处的 @Autowired 可以省略
    public  StudentController (UserService userService) {
        this.userService = userService;
    }

    public void sayHi() {
        System.out.println("student controller say hi");
        userService.sayHi();
    }
}

运行结果:


优点

1、可以注入一个不可变对象(即用 final 关键字修饰的对象)

  • 被 final 关键字修饰的对象必须满足以下两个条件中的任意一个
  • final 修饰的对象,要么需直接赋值
  • final 修饰的对象,要么需通过构造方法赋值

2、注入对象后不会被修改

  • 构造方法随着类加载仅执行一次

3、构造方法注入可以保证对象完全被完全初始化

  • 当创建一个对象时,一定会调用该类的构造方法来初始化该对象
  • 所以通过构造方法注入时,将必然保证该对象已经是被 Spring 容器所注入了 Bean 对象的

4、相比属性注入,构造方法注入的兼容性更好

  • 构造方法注入可适用于任何环境,无论是 IoC 框架还是非 IoC 框架

 @Resource

  • @Resource 注解由 JDK 所提供

@Autowired 和 @Resource 的区别

  • 出身不同:@Autowired 来自于 Spring,而 @Resource 来自于 JDK
  • @Autowired 可用于 属性注入、Settter 注入、构造函数注入,而 @Resource 只能用于 属性注入、Setter 注入
  • 使用时设置的参数不同:相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如 重命名

@Autowired 和 @Resource 查找 Bean 对象的区别

  • @Autowired 先会根据类型查找,之后再根据名称查找
  • 而 @Resource 会先根据名称来查,再根据类型查找

实例理解

  • 我们创建一个实体类
// 普通的用户实体类
public class User {
    public Integer uid;
    public String username;
    public String password;
    public Integer age;

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
  • 再创建一个 UserBean 类,通过该类向 Spring 容器中注入 User 的 Bean 对象
import com.java.demo.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class UserBeans {
    @Bean
    public User getUserByName() {
        User user = new User();
        user.setUid(1);
        user.setUsername("张三");
        user.setPassword("123456");
        user.setAge(18);
        return user;
    }

    @Bean(name = {"user1","u1"})
    public User getUserById() {
        User user = new User();
        user.setUid(1);
        user.setUsername("李四");
        user.setPassword("123456");
        user.setAge(18);
        return user;
    }
}
  •  User 的 Bean 对象通过 @Autowired 注入到 StudentController 类中
import com.java.demo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

// 使用 @Controller 注解将当前类存储到 spring 容器中
@Controller
public class StudentController {

    //    使用 属性 注入
    @Autowired
    private User user;

    public void sayHi() {
        System.out.println("student controller say hi");
        user.getUsername();
    }
}

运行结果:

报错分析:

  • 正因为我们在 UserBeans 类中向 Spring 容器注入了两个同为 User 类型的 Bean 对象
  • 所以当我们使用 @Autowired 注解来注入 Bean 对象的时候,它会先根据类型来查找

  • 那此时便在 Spring 容器中查找到了 两个同为 User 类型的 Bean 对象 
  • 从而 将会根据绿框名称来查找,若 Spring 容器中有 id 为 user 的 Bean 对象,便会直接注入

  • 但是我们存入 Spring 容器中的 User 类型的 Bean 对象,其一 id 为 getUserByName,其二 id 为 user1 或 u1
  • 所以 @Autowired 找不到 id 为 user 的 Bean 对象,从而发生报错

解决方法:

方案一:

  • 修改绿框名称,通过 id 来指定注入一个 Bean 对象 

方案二:

  • 使用 @Resource 注解,通过设置参数来查找

  • 当然本应将参数名称设置为 user1 来实现依赖注入的
  • 使用该方式,可以实现 参数名称 的重命名

方案三:

  • 组合使用 @Autowired 和 @Qualifier 注解

  • @Qualifier 注解起到筛选的作用,筛选出 id 为 user1 的 Bean 对象,并将其注入
  • 该方式所呈现的效果 与 方式二 相同

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

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

相关文章

Park和UnPark底层原理

文章目录 1. 简介2. 底层原理3. 总结 1. 简介 park和unpark也是一个线程暂停技术&#xff08;让线程进入wait状态&#xff09;&#xff0c;与wait/notify不同的是&#xff0c;前者是LockSupport类中的方法&#xff0c;后者是Object类中的方法。其次&#xff0c;wait与notify和…

Makefile 介绍

目录 一、Makefile 的规则 二、一个示例 三、make 是如何工作的 四、makefile 中使用变量 五、让 make 自动推导 六、另类风格的 makefile 七、清空目标文件的规则 make 命令执行时&#xff0c;需要一个 Makefile 文件&#xff0c;以告诉 make 命令需要怎么样的去编译和…

1.docker linux离线环境安装 20.1.0.12

目录 概述下载解压docker 卸载docker 安装检查安装环境常用命令结束 概述 docker离线环境安装 20.1.0.12 , centos 7.x 下载 安装包下载 解压 [roothadoop01 soft]# unzip docker_20_1_0_12.zip [roothadoop01 soft]# cd docker_20_1_0_12 [roothadoop01 docker_20_1_0_1…

Java系统操作日志之数据修改变化记录

系统操作日志之数据修改变化记录 前言效果图如何实现总结 相信大家在自己的系统中都有记录日志吧&#xff0c;像登录日志、操作日志等等 但是一般来说&#xff0c;大家都是获取操作了什么东西&#xff0c;包括它的参数&#xff0c;模块等等&#xff0c;但是你有关心过他的数据变…

06【保姆级】-GO语言的运算符

之前我学过C、Java、Python语言时总结的经验&#xff1a; 先建立整体框架&#xff0c;然后再去抠细节。先Know how&#xff0c;然后know why。先做出来&#xff0c;然后再去一点点研究&#xff0c;才会事半功倍。适当的囫囵吞枣。因为死抠某个知识点很浪费时间的。对于GO语言&a…

使用MCU上的I2C总线进行传感器应用

使用MCU上的I2C总线进行传感器应用是嵌入式系统开发中常见的任务&#xff0c;本文将介绍在MCU上实现I2C总线传感器应用的相关技术和流程。 首先&#xff0c;I2C&#xff08;Inter-Integrated Circuit&#xff09;总线是一种常用的串行通信协议&#xff0c;用于连接多个设备&am…

2023/11/8JAVA学习

多个条件也可以&&放在一块,支持链式编程 map()数据加工,一个对象转化为另一个 不能这样写 不会去重报错

java入门,记一次mysql函数使用

一、前言 记一次mysql函数使用&#xff0c;要求给一个字段进行拼接&#xff0c;然后MD5加密&#xff0c;再转换成大写。这里都是有现成的函数&#xff0c;所以记录下来 二、函数使用 1、拼接函数&#xff1a; concat(字符串1,字符串2) select concat(字符串1,字符串2); 2、…

Postman使用方法详细攻略

一、Postman背景介绍 用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的&#xff0c;用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具。今天给大家介绍的这款网页调试工具不仅可以调试简单的css、html、脚本等简单的网…

APISpace IP归属地查询接口案例代码

1.IP归属地查询API 1.1 API接口简介 IP归属地查询API&#xff1a;根据IP地址查询归属地信息&#xff0c;包含国家、省、市、区县和运营商等信息。APISpace 提供了IPv4 和 IPv6 的IP归属地查询接口&#xff0c;并且包含了各种归属地精度查询的接口。 1.2 IPv4 IPv4归属地查询…

数据结构与算法-(11)---有序表(OrderedList)

&#x1f308;个人主页: Aileen_0v0 &#x1f525;系列专栏:PYTHON学习系列专栏 &#x1f4ab;"没有罗马,那就自己创造罗马~" 目录 知识回顾及总结 有序表的引入 ​编辑 实现有序表 1.有序表-类的构造方法 2.有序表-search方法的实现 3.有序表-add方法的实现…

电气元器件的型号,符号,接线认识(一)

目录 按钮开关 类型 文字与图形符号 常开常闭触点 接线图 中间继电器 实物图 文字与图形符号 接线图 交流接触器 实物图 文字与图形符号 接线图 开关电源 图形 文字与图形符号 接线图 断路器 实物图 类型 文字与图形符号 接线图 今天让我们来认识一下电路元…

ci-cd的流程

1、项目在gitlab上&#xff0c;从gitlab上使用git插件获取源码&#xff0c;构建成war包&#xff0c;所以使用tomcat作为运行环境 发布 &#xff1a;使用maven插件发布&#xff0c;使用ssh连接。

大众动力总成构建全程数字化的数电票管理平台

客户简介 上海大众动力总成有限公司成立于2005年4月29日&#xff0c;是德国大众在中国的全资投资公司大众汽车&#xff08;中国&#xff09;投资有限公司和上海汽车集团股份有限公司合资组建的发动机生产企业&#xff0c;是世界上加工工艺和技术水平最先进的发动机生产基地之一…

kubernetes集群编排(8)

k8s资源监控 资源限制 上传镜像 [rootk8s2 limit]# vim limit.yaml apiVersion: v1 kind: Pod metadata:name: memory-demo spec:containers:- name: memory-demoimage: stressargs:- --vm- "1"- --vm-bytes- 200Mresources:requests:memory: 50Milimits:memory: 100…

使用EvoMap/Three.js模拟无人机灯光秀

一、创建地图对象 首先我们需要创建一个EM.Map对象&#xff0c;该对象代表了一个地图实例&#xff0c;并设置id为"map"的文档元素作为地图的容器。 let map new EM.Map("map",{zoom:22.14,center:[8.02528, -29.27638, 0],pitch:71.507,roll:2.01,maxPit…

在linux中配置固定ip

1、在虚拟机中配置网络&#xff0c;改ONBOOTyes后默认直接DHCP自动获取ip&#xff0c;但是这种方法会导致ip改变。这个时候&#xff0c;我们需要配置固定ip 2、进入/etc/sysconfig/network-scripts查看ifcfg-ens33 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOdh…

Flink之状态管理

Flink状态管理 状态概述状态分类 键控、按键分区状态概述值状态 ValueState列表状态 ListStateMap状态 MapState归约状态 ReducingState聚合状态 Aggregating State 算子状态概述列表状态 ListState联合列表状态 UnionListState广播状态 Broadcast State 状态有效期 (TTL)概述S…

Kubernetes7大网络插件之Antrea

目录 前言 Antrea简介 Antrea安装使用 下载Antrea YAML文件 编辑YAML文件 应用YAML文件 等待安装完成 配置网络策略 测试 创建命名空间 部署两个Nginx Pod 定义网络策略 测试网络策略 前言 在现代容器化应用程序的世界中&#xff0c;容器编排平台Kubernetes已经成为…

Mybatis-Plus同时使用逻辑删除和唯一索引的问题及解决办法

1 问题背景 在开发中&#xff0c;我们经常会有逻辑删除和唯一索引同时使用的情况。但当使用mybatis plus时&#xff0c;如果同时使用逻辑删除和唯一索引&#xff0c;会报数据重复Duplicate entry的问题。 举例来说&#xff0c;有表user&#xff0c;建立唯一索引&#xff08;u…