详解Spring依赖注入的三种方式以及优缺点

目录
  • 0.概述
  • 1.属性注入
    • 1.1 优点分析
    • 1.2 缺点分析
  • 2.Setter 注入
    • 优缺点分析
  • 3.构造方法注入
    • 优点分析
  • 总结

0.概述

在 Spring 中实现依赖注入的常见方式有以下 3 种:

  • 属性注入(Field Injection);
  • Setter 注入(Setter Injection);
  • 构造方法注入(Constructor Injection)。

它们的具体使用和优缺点分析如下。

1.属性注入

属性注入是我们最熟悉,也是日常开发中使用最多的一种注入方式,它的实现代码如下:

@RestController
public class UserController {
    // 属性对象
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

1.1 优点分析

属性注入最大的优点就是实现简单、使用简单,只需要给变量上添加一个注解(@Autowired),就可以在不 new 对象的情况下,直接获得注入的对象了(这就是 DI 的功能和魅力所在),所以它的优点就是使用简单。

1.2 缺点分析

然而,属性注入虽然使用简单,但也存在着很多问题,甚至编译器 Idea 都会提醒你“不建议使用此注入方式”,Idea 的提示信息如下:

属性注入的缺点主要包含以下 3 个:

  • 功能性问题:无法注入一个不可变的对象(final 修饰的对象);
  • 通用性问题:只能适应于 IoC 容器;
  • 设计原则问题:更容易违背单一设计原则。

接下来我们一一来看。

缺点1:功能性问题

使用属性注入无法注入一个不可变的对象(final 修饰的对象),如下图所示:

原因也很简单:在 Java 中 final 对象(不可变)要么直接赋值,要么在构造方法中赋值,所以当使用属性注入 final 对象时,它不符合 Java 中 final 的使用规范,所以就不能注入成功了。

PS:如果要注入一个不可变的对象,要怎么实现呢?使用下面的构造方法注入即可。

缺点2:通用性问题

使用属性注入的方式只适用于 IoC 框架(容器),如果将属性注入的代码移植到其他非 IoC 的框架中,那么代码就无效了,所以属性注入的通用性不是很好。

缺点3:设计原则问题

使用属性注入的方式,因为使用起来很简单,所以开发者很容易在一个类中同时注入多个对象,而这些对象的注入是否有必要?是否符合程序设计中的单一职责原则?就变成了一个问题。

但可以肯定的是,注入实现越简单,那么滥用它的概率也越大,所以出现违背单一职责原则的概率也越大

注意:这里强调的是违背设计原则(单一职责)的可能性,而不是一定会违背设计原则,二者有着本质的区别。

2.Setter 注入

Setter 注入的实现代码如下:

@RestController
public class UserController {
    // Setter 注入
    private UserService userService;

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

    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

优缺点分析

从上面代码可以看出,Setter 注入比属性注入要麻烦很多。

要说 Setter 注入有什么优点的话,那么首当其冲的就是它完全符合单一职责的设计原则,因为每一个 Setter 只针对一个对象

但它的缺点也很明显,它的缺点主要体现在以下 2 点:

  • 不能注入不可变对象(final 修饰的对象);
  • 注入的对象可被修改。

接下来我们一一来看。

缺点1:不能注入不可变对象

使用 Setter 注入依然不能注入不可变对象,比如以下注入会报错:

缺点2:注入对象可被修改

Setter 注入提供了 setXXX 的方法,意味着你可以在任何时候、在任何地方,通过调用 setXXX 的方法来改变注入对象,所以 Setter 注入的问题是,被注入的对象可能随时被修改

3.构造方法注入

构造方法注入是 Spring 官方从 4.x 之后推荐的注入方式,它的实现代码如下:

@RestController
public class UserController {
    // 构造方法注入
    private UserService userService;

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

    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

当然,如果当前的类中只有一个构造方法,那么 @Autowired 也可以省略,所以以上代码还可以这样写:

@RestController
public class UserController {
    // 构造方法注入
    private UserService userService;

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

    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

优点分析

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

  • 可注入不可变对象;
  • 注入对象不会被修改;
  • 注入对象会被完全初始化;
  • 通用性更好。

接下来我们一一来看。

优点1:注入不可变对象

使用构造方法注入可以注入不可变对象,如下代码所示:

优点2:注入对象不会被修改

构造方法注入不会像 Setter 注入那样,构造方法在对象创建时只会执行一次,因此它不存在注入对象被随时(调用)修改的情况。

优点3:完全初始化

因为依赖对象是在构造方法中执行的,而构造方法是在对象创建之初执行的,因此被注入的对象在使用之前,会被完全初始化,这也是构造方法注入的优点之一。

优点4:通用性更好

构造方法和属性注入不同,构造方法注入可适用于任何环境,无论是 IoC 框架还是非 IoC 框架,构造方法注入的代码都是通用的,所以它的通用性更好。

总结

依赖注入的常见实现方式有 3 种:属性注入、Setter 注入和构造方法注入。其中属性注入的写法最简单,所以日常项目中使用的频率最高,但它的通用性不好;而 Spring 官方推荐的是构造方法注入,它可以注入不可变对象,其通用性也更好,如果是注入可变对象,那么可以考虑使用 Setter 注入。

以上就是详解Spring依赖注入的三种方式以及优缺点的详细内容,更多关于Spring依赖注入的资料请关注我们其它相关文章!

(0)

相关推荐

  • spring依赖注入知识点分享

    spring与IoC IoC:控制反转,将由代码操纵的对象控制权,交给第三方容器,反转给第三方容器.这种对象依赖的关系管理方式,称作 IoC.IoC是一个思想,概念.比较 著名的两种方式: DL(Dependency Lookup)依赖查找,典型的是JNDI.java名称与服务接口. DI(Dependency Injection)依赖注入.是目前最优秀的接耦合方式.典型应用spring. spring的DI 依赖注入,即:为属性赋值. xml实现 1)设值注入 底层调用属性的setter方法进

  • Spring依赖注入的几种方式分享梳理总结

    目录 环境 准备 设值注入 构造注入 总结 环境 Ubuntu 22.04 IntelliJ IDEA 2022.1.3 JDK 17.0.3 Spring 5.3.21 准备 创建Maven项目 test0706 . 修改 pom.xml 文件,添加依赖: ...... <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId>

  • Spring 依赖注入实现示例

    [注]本文译自:https://springframework.guru/...   在本文中,我将向你展示如何在 Spring Framework 的依赖项注入中使用 Project Lombok 以获得最佳实践.   Spring 框架本身具有多种执行依赖项注入的方式.选项的灵活性是 Spring 框架的优势.但是,并非所有的依赖项注入选项都被视为最佳实践.有些实际上不太好. 依赖注入示例   我提供了一些设置示例,供我们查看必须使用的各种依赖项注入选项.   让我们以 Spring Ser

  • Spring依赖注入的三种方式小结

    Spring的主要特性包括IOC和DI,其中DI是IOC的基础.在以前的Spring使用过程中大部分都是使用XML配置文件显式配置spring组件,导致大量的XML配置文件以及冗余的XML配置代码.阅读<Spring in Action>后总结Spring的DI功能的三种主要装配方式以及混合装配方式 根据注解自动装配 Spring中有非常丰富的注解,通过这些注解可以方便地配置Spring容器,使得Spring容器可以自动识别相关Bean并做自动注入装配. 使用注解 @Component注解:标

  • spring IOC中三种依赖注入方式

    一.Spring IOC(依赖注入的三种方式): 1.Setter方法注入. 2.构造方法注入. 使用构造方法,注入bean值. 关键代码: public UserServiceImpl(UserDao dao) { this.dao=dao; } <bean id="service" class="service.impl.UserServiceImpl"> <constructor-arg><ref bean="dao&q

  • 详解Spring依赖注入的三种方式以及优缺点

    目录 0.概述 1.属性注入 1.1 优点分析 1.2 缺点分析 2.Setter 注入 优缺点分析 3.构造方法注入 优点分析 总结 0.概述 在 Spring 中实现依赖注入的常见方式有以下 3 种: 属性注入(Field Injection): Setter 注入(Setter Injection): 构造方法注入(Constructor Injection). 它们的具体使用和优缺点分析如下. 1.属性注入 属性注入是我们最熟悉,也是日常开发中使用最多的一种注入方式,它的实现代码如下:

  • 详解Spring获取配置的三种方式

    目录 前言 Spring中获取配置的三种方式 通过@Value动态获取单个配置 通过@ConfigurationProperties+前缀方式批量获取 通过Environment动态获取单个配置 总结 前言 最近在写框架时遇到需要根据特定配置(可能不存在)加载 bean 的需求,所以就学习了下 Spring 中如何获取配置的几种方式. Spring 中获取配置的三种方式 通过 @Value 方式动态获取单个配置 通过 @ConfigurationProperties + 前缀方式批量获取配置 通

  • Spring依赖注入的三种方式实例详解

    Spring依赖注入(DI)的三种方式,分别为: 1. 接口注入 2. Setter方法注入 3. 构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个类: 接口 Logic.java 接口实现类 LogicImpl.java 一个处理类 LoginAction.java 还有一个测试类 TestMain.java Logic.java如下: package com.spring.test.di; public interface Logic { pub

  • 详解Spring全局异常处理的三种方式

    在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的.不可预知的异常需要处理.每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大. 那么,能不能将所有类型的异常处理从各处理过程解耦出来,这样既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护?答案是肯定的.下面将介绍使用Spring MVC统一处理异常的解决和实现过程 使用Spring MVC提供的SimpleMappingE

  • Spring依赖注入(DI)两种方式的示例详解

    目录 一.依赖注入方式 二.setter注入 引用类型 简单类型 三.构造器注入 引用类型 简单类型 参数适配(了解) 四.依赖注入方式选择 一.依赖注入方式 思考:向一个类中传递数据的方式有几种? 普通方法(set方法) 构造方法 思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢? 引用类型 简单类型(基本数据类型与String) 依赖注入方式: setter注入 简单类型 引用类型 构造器注入 简单类型 引用类型 二.setter注

  • 详解Spring集成Redis的两种方式

    目录 一.使用Jedis方式集成 1.增加依赖 2.配置项 3.配置连接池 4.测试 使用spring-data-redis 1.引入依赖 2.配置项 3.使用 4.可能会遇到的坑 哨兵和集群 总结: 在工作中,我们用到分布式缓存的时候,第一选择就是Redis,今天介绍一下SpringBoot如何集成Redis的,分别使用Jedis和Spring-data-redis两种方式. 一.使用Jedis方式集成 1.增加依赖 <!-- spring-boot-starter-web不是必须的,这里是为

  • 详解SpringBoot禁用Swagger的三种方式

    目录 摘要 方法 禁用方法1: 禁用方法2: 禁用方法3: 摘要 在生产环境下,我们需要关闭swagger配置,避免暴露接口的这种危险行为. 方法 禁用方法1: 使用注解 @Value() 推荐使用 package com.dc.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Be

  • 详解Springboot下载Excel的三种方式

    汇总一下浏览器下载和代码本地下载实现的3种方式. (其实一般都是在代码生成excel,然后上传到oss,然后传链接给前台,但是我好像没有实现过直接点击就能在浏览器下载的功能,所以这次一起汇总一下3种实现方式.)

  • 详解mysql数据去重的三种方式

    目录 一.背景 二.数据去重三种方法使用 1.​通过MySQL DISTINCT:去重(过滤重复数据) 2.group by 3.row_number窗口函数 三.总结 一.背景 最近在和系统模块做数据联调,其中有一个需求是将两个角色下的相关数据​对比后将最新的数据返回出去,于是就想到了去重,再次做一个总结. 二.数据去重三种方法使用 1.​通过MySQL DISTINCT:去重(过滤重复数据) ​ 1.1.在使用 mysql SELECT 语句查询数据的时候返回的是所有匹配的行. SELECT

随机推荐