【Spring】三大依赖注入(@Autowired,Setter,构造方法)

这篇具有很好参考价值的文章主要介绍了【Spring】三大依赖注入(@Autowired,Setter,构造方法)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、属性注入(@Autowired)

1.1 优点分析

1.2 缺点分析

1.2.1 无法实现final修饰的变量注入。

1.2.2 兼容性不好

1.2.3 (可能违背)设计原则问题

1.2.4 代码举例:

1.2.5 出现循环依赖该怎么办?

1.2.6 @Resource与@Autowired的区别

二、Setter注入

2.1 优点分析

2.2 缺点分析

2.2.1 不能注入不可变对象

2.2.2 注入对象可被修改

三、构造方法注入

3.1 优点分析

3.1.1 可注入不可变对象

3.1.2 注入对象不会被修改

3.1.3 注入对象会被完全初始化

3.1.4 通用性更好


一、属性注入(@Autowired)

属性注入是使用@Autowired实现的,如下:将UserService类注入到UserController类中:

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

启动类如下:

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

运行结果如下:

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

1.1 优点分析

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

1.2 缺点分析

1.2.1 无法实现final修饰的变量注入。

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

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

问:那么如果要注入一个不可变的对象,该如何实现呢?

答;使用构造方法注入。

1.2.2 兼容性不好

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

1.2.3 (可能违背)设计原则问题

属性注入容易违背单一设计原则是因为它会导致类的职责不够单一,在属性注入中,一个类可能会同时拥有多个依赖,这些依赖可能与该类的主要职责无关,导致类的职责不够单一,使代码变得难以维护。

而单一设计原则的核心思想是:一个类应该只有一个职责,只有这样才能使代码易于维护和扩展,因此,在使用属性注入时,特别需要注意类的职责是否清晰,以及注入的属性是否与类的主要职责相关。

当然,也不是说一定会出现违背单一原则的情况,但是不可否认的是:注入实现越简单,那么滥用它的概率也越大,所以出现违背单一职责原则的概率也越大。 注意:这里强调的是违背设计原则(单一职责)的可能性,而不是一定会违背设计原则,二者有着本质的区别。

1.2.4 代码举例:

当使用@Autowired注入时,一个类可能会依赖于多个其他类或接口,这样会导致这个类的职责过重,违反了单一设计原则。下面是一个例子:

假设有一个OrderService类,它需要依赖于一个UserService和一个ProductService来完成一些业务逻辑。如果使用@Autowired注入这两个依赖,那么OrderService将会依赖于UserService和ProductService两个类,导致OrderService职责过重。

@Service
public class OrderService {
 
    @Autowired
    private UserService userService;
 
    @Autowired
    private ProductService productService;
 
    public void placeOrder() {
        // use userService and productService to place order
    }
}

这里OrderService类的职责包含了用户管理和商品管理,这违反了单一设计原则。如果将UserService和ProductService作为方法参数传递,而不是使用@Autowired注入,那么OrderService就只需要关注订单管理相关的逻辑,而不需要依赖其他的类或接口,符合单一设计原则。

1.2.5 出现循环依赖该怎么办?

什么是循环依赖?

在Spring中,当一个bean被初始化时,如果依赖的bean还未初始化,Spring会把该bean放入一个专门用来存储正在初始化的bean的缓存中,以便在依赖的bean初始化完成后再将其注入。但如果两个bean相互依赖,那么它们的初始化顺序就会产生死锁,导致应用程序无法启动。

@Autowired注入可以让类和类之间的关系变得紧密,容易出现循环依赖和复杂的依赖关系,从而违反了单一设计原则中的“高内聚,低耦合”的原则。

以下是一个例子:

public class OrderService {
    @Autowired
    private UserService userService;
    
    public void createOrder() {
        // 创建订单代码
        User user = userService.getUser();
        // 订单相关代码
    }
}

public class UserService {
    @Autowired
    private OrderService orderService;
    
    public User getUser() {
        // 获取用户代码
        Order order = orderService.getOrder();
        // 用户相关代码
    }
}

在这个例子中,OrderService和UserService互相依赖,存在循环依赖关系(具体来说,当容器创建bean A时,会发现A需要依赖B,于是容器会先创建bean B,但是创建B又发现B需要依赖A,于是容器又会回去创建bean A,这样就形成了循环依赖的问题。)。这使得系统中类之间的依赖关系变得复杂,不利于代码的维护和扩展。

为了解决这个问题,可以采用构造函数注入来替代@Autowired注入。构造函数注入避免循环依赖问题,并且更容易维护和测试。例如,可以通过以下方式来进行改进:

public class OrderService {
    private UserService userService;
    
    public OrderService(UserService userService) {
        this.userService = userService;
    }
    
    public void createOrder() {
        // 创建订单代码
        User user = userService.getUser();
        // 订单相关代码
    }
}

public class UserService {
    private OrderService orderService;
    
    public UserService(OrderService orderService) {
        this.orderService = orderService;
    }
    
    public User getUser() {
        // 获取用户代码
        Order order = orderService.getOrder();
        // 用户相关代码
    }
}

在这个改进后的代码中,通过构造函数注入的方式来避免了循环依赖问题,并且更加符合单一设计原则中的“高内聚,低耦合”的原则。

可能有人会说,Spring框架不是提供了三级缓存的方案来解决循环依赖吗?

为了解决循环依赖的问题,Spring确实是使用了三级缓存来管理bean的创建和初始化过程:

具体来说,当Spring创建bean时,会将该bean放入三级缓存中,其中第一级缓存存储已经完成了实例化的bean,第二级缓存存储已经完成了属性注入的bean,第三级缓存存储还未完成属性注入的bean。在注入属性时,Spring会首先从第一级缓存中查找bean,如果找不到则继续到第二级缓存中查找,如果还是找不到则继续到第三级缓存中查找,如果最终还是找不到,则会抛出异常。

既然提供了三级缓存,为什么还要关心注入会不会出现依赖注入的情况呢?

虽然Spring框架提供了三级缓存的方案来解决循环依赖,但是使用@Autowired注解的确可能会引起循环依赖的问题。而且,如果循环依赖链条较长,缓存的效率会受到影响,甚至会导致系统性能下降。

另外,对于大型系统来说,循环依赖是一种设计上的问题,不应该在代码实现时去“绕过”这个问题,而应该通过优化代码结构、拆分模块等方式来解决。

总的来说,虽然Spring框架提供了循环依赖的解决方案,但是在实际使用时,应该避免产生循环依赖的情况,从设计层面上避免这个问题的发生,提高系统的稳定性和可维护性。

注意这里不能使用Setter注入来解决循环依赖问题:

setter注入可以一定程度上避免循环依赖的问题,但并不是完全解决。setter注入是通过在bean初始化完成之后,逐一为属性赋值来完成注入的,因此可以避免在构造函数中进行依赖注入时可能产生的循环依赖问题。

但是如果在setter注入中,存在多个bean相互依赖的情况,仍然有可能产生循环依赖。例如,beanA中有属性a,需要通过setter注入来完成,而属性a又需要引用beanB中的属性b,那么就会产生循环依赖的问题。

为了避免循环依赖的问题,可以通过三种方式解决:

  1. 构造函数注入:在构造函数中注入依赖,从而避免setter注入中可能出现的循环依赖问题。

  2. 使用延迟依赖注入:在注入时不直接注入依赖,而是通过代理对象实现延迟注入,当真正需要使用该依赖时,再进行注入。

  3. 使用工厂模式:通过工厂模式来管理bean的创建和依赖注入,从而解决循环依赖问题。

1.2.6 @Resource与@Autowired的区别

在进行类注入的时候,除了可以使用@Autowired之外,还可以使用@Resource进行注入,如下代码所示:

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

@Autowired和@Resource的区别

  • 出身不同:@Autowired来自于Spring,而Resource来自于JDK的注解。
  • 使用时设置的参数不同:相比于@Autowired来说,@Resource支持更多的参数设置,例如name设置——可以根据名称获取Bean。
  • @Autowired可用于Setter注入,构造方法注入和熟悉注入,而@Resource只能用于Setter注入和属性注入,不能用于构造方法注入。
  • 查找顺序不同:@Autowired是先根据类型查找,再根据名称查找,而@Resource是根据名称查找,再根据类型查找。

同⼀类型多个 @Bean 报错

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

代码报错:

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

这是因为我们在Spring中并没有存储user1的Bean对象:

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

@Resource可配合参数name在Spring中查找类:

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

而@Autowired可以配合@Qualifier使用:

【Spring】三大依赖注入(@Autowired,Setter,构造方法)

二、Setter注入

setter注入是指将一个类的依赖通过设置一个公共的setter方法注入到该类中,这样就能够让该类使用这个依赖。setter方法通常在类中定义为public,并且以set开头,接着是一个单词,表示注入的属性的名称,例如:

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

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

    public void sayHi() {
        System.out.println("com.java.demo -> do UserController sayHI()");
        userService.sayHi();
    }
}

2.1 优点分析

可以看出,Setter注入其实是比属性注入要麻烦的,但是其也是有优点的,那就是它完全符合单一职责的设计原则,因为每个Setter只针对一个对象。

2.2 缺点分析

2.2.1 不能注入不可变对象

与@Autowired相同,Setter注入是不能注入不可变对象的:【Spring】三大依赖注入(@Autowired,Setter,构造方法)

2.2.2 注入对象可被修改

Setter注入提供了setXXX的方法,意味着开发者可以在任意时刻,任何地方,通过调用setXXX方法来改变注入对象。

三、构造方法注入

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

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

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
    public void sayHi() {
        System.out.println("com.java.demo -> do UserController sayHI()");
        userService.sayHi();
    }
   
}

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

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

   
    public UserController(UserService userService) {
        this.userService = userService;
    }
    public void sayHi() {
        System.out.println("com.java.demo -> do UserController sayHI()");
        userService.sayHi();
    }
   
}

3.1 优点分析

3.1.1 可注入不可变对象

使用构造方法是可以注入不可变对象的,以下代码实现:

@Controller
public class UserController {

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


    public void sayHi() {
        System.out.println("com.java.demo -> do UserController sayHI()");
        userService.sayHi();
    }
}

3.1.2 注入对象不会被修改

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

3.1.3 注入对象会被完全初始化

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

3.1.4 通用性更好

构造方法和属性注入不同,构造方法注入可适用于任何环境,无论是IoC框架还是非IoC框架,构造方法注入的代码都是通用的,所以它的通用性更好。文章来源地址https://www.toymoban.com/news/detail-429025.html

到了这里,关于【Spring】三大依赖注入(@Autowired,Setter,构造方法)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用 @Autowired 依赖注入时警告不建议使用字段注入

    在 Spring 中注入依赖时有 字段注入 、 构造器注入 、S etter 方法注入 三种注入方式。 无法注入 final 字段 在 Spring 2.5 中引入了 @Autowired 注解,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。在成员变量上使用 @Autowired 注解可以进行字段注入,如下:

    2024年02月05日
    浏览(31)
  • 【Spring】—— setter注入

    1、提供可访问的set方法 2、配置中注入引用类型对象   property标签:         ref属性注入的是引用类型对象(第一个bean标签的id),         name属性是前面set方法中的参数名称。  上面是引用类型注入, 简单类型注入set方法和上面相同,配置中property标签value属性是具

    2024年01月17日
    浏览(24)
  • spring如何进行依赖注入,通过set方法把Dao注入到serves

    你在service层后面方法的这些:   最后我们执行一下 :  什么叫做依赖注入,serve应该于Dao的注入我就通过配置文件在容器中注把他注给他: 配置文件:  依赖注入有个简单方法,把properties那个子标签:  就是把这个子标签给省掉他: 1、如何引入,首先打开配置文件: 当我

    2024年02月12日
    浏览(29)
  • Spring Boot——@Autowired属性注入问题

    当我们在使用 @Autowired 属性注入时,会发现idea提示 Field injection is not recommended ,译为: 不推荐使用属性注入   要想了解Spring和idea之所以不推荐使用@Autowired属性注入,首先就要先了解Spring常用的注入方式:简单类型注入、集合类型注入, 域属性自动注入, 自动注入的类别, 空值注

    2024年02月06日
    浏览(35)
  • JavaSE学习之路:Idea小技巧一键生成标准JavaBean(一键生成构造方法和Setter和Getter方法)

    1.生成有参和无参构造函数 2.生成Getter和Setter方法 3.生成toString方法 1.安装插件 2.右键-使用插件

    2024年02月12日
    浏览(27)
  • Springboot依赖注入Bean的三种方式,final+构造器注入Bean

    @Autowired注解的一大使用场景就是Field Injection。 通过Java的反射机制实现,所以private的成员也可以被注入具体的对象 优点 代码少,简洁明了。 新增依赖十分方便,不需要修改原有代码 缺点 容易出现空指针异常。Field 注入允许构建对象实例时依赖的对象为空,导致空指针异常

    2024年02月02日
    浏览(39)
  • Spring Boot进阶(57):Spring中什么时候不要用@Autowired注入 | 超级详细,建议收藏

            注解@Autowired,相信对于我们Java开发者而言并不陌生吧,在SpringBoot或SpringCloud框架中使用那是非常的广泛。但是当我们使用IDEA编辑器开发代码的时候,经常会发现@Autowired 注解下面提示小黄线警告,我们把小鼠标悬停在注解上面,可以看到这个如下图所示的警告信息

    2024年02月16日
    浏览(31)
  • VS依赖注入(DI)构造函数自动生成局部私有变量

    依赖注入(DI)在开发中既是常见的也是必需的技术。它帮助我们优化了代码结构,使得应用更加灵活、易于扩展,同时也降低了各个模块之间的耦合度,更容易进行单元测试,提高了编码效率和质量。我们经常会先定义局部变量,再在构造函数中使用,每次都要这样去编写耗时

    2024年02月11日
    浏览(33)
  • springboot中@Autowired 注入失效的四种原因及解决方法

    1. 被注入的对象没有加载到spring容器中 通常是因为被注入的对象没有被spring扫描到,此时需要添加对应的包扫描路径。 2. 需要自动注入的对象不是spring加载,而是new的方式创建 由于对象不是spring创建的,当然spring也就无法根据注解自动注入对应的实例对象。 此时可以采用代

    2024年02月16日
    浏览(24)
  • 【注解使用】使用@Autowired后提示:Field injection is not recommended(Spring团队不推荐使用Field注入)

    在使用 IDEA 开发 SpringBoot 项目时,在  Controller  类中使用注解  @Autowired  注入一个依赖出现了警告提示,查看其他使用该注解的地方同样出现了警告提示。这是怎么回事?由于先去使用了SpringBoot并没有对Spring进行系统性学习,所以做一个记录。 Field injection is not recommended(

    2024年02月12日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包