Spring从零开始学使用系列(三)--依赖注入(DI)

目录

1.DI的核心概念

1.1优势

2. Spring中的DI实现

2.1 构造器注入

2.1.2 优势和缺点

2.2 设置器注入

 2.2.1 如何使用设置器注入

2.2.2 示例代码

2.2.3优势和使用场景

 2.3 字段注入

2.4 方法注入

2.4.1 方法注入的概念

2.4.2 找方法注入

2.4.3 @Lookup 注解的作用

2.4.4 结论和最佳实践

2.5 总结

3.Spring事务管理概述

3.1 声明式事务管理

3.1.1 使用@Transactional注解

3.1.2 @Transactional注解的参数解释

3.1.3 Spring Data JPA 和事务

3.2 事务传播行为

3.3事务失效的场景

4.总结


1.DI的核心概念

        依赖注入(DI)是一种设计模式,用于实现对象间的依赖关系的自动满足。在传统的编程模式中,每个对象负责管理其依赖项的创建和绑定,而在使用DI的模式中,这些依赖项是由外部系统(在Spring中是IoC容器)在创建对象时自动注入的。

1.1优势
  • 降低耦合度:对象不需要知道如何创建它们所需的依赖对象。
  • 增强模块化:便于管理大型应用中的依赖关系。
  • 提高可测试性:依赖可以在测试中被替换或模拟。
2. Spring中的DI实现

        Spring提供了多种方式来实现DI,包括构造器注入、设置器注入和字段注入。

2.1 构造器注入

        通过构造器注入,依赖项在对象创建时通过构造函数传入。这是推荐的注入方式,因为它可以保证所需的依赖项在使用前就被正确提供。

@Component
public class ProductService {
    private final InventoryService inventoryService;

    public ProductService(InventoryService inventoryService) {
        this.inventoryService = inventoryService;
    }
}

        在Spring 4.3之后,如果目标组件只定义了一个构造器,Spring会自动将其作为用于依赖注入的构造器,无需显式使用@Autowired注解。然而,在更早的版本中或者当存在多个构造器时,@Autowired是必须的,以标识哪个构造器应该被用来自动注入。

2.1.2 优势和缺点

优点

  • 依赖不可变,确保所需的依赖在使用前已经提供。
  • 便于发现缺失的依赖,因为在对象创建时就会出错。
  • 最适合用于必需依赖。

缺点

  • 如果依赖项很多,构造器可能会显得笨重。
  • 对于可选依赖不是很灵活。
2.2 设置器注入

        设置器注入,顾名思义,是通过类的设置方法(setter方法)来注入依赖。这种方式的主要特点是它不强制在构造对象时立即提供依赖,而是允许在对象构造后、使用前的任何时间点注入依赖。这提供了更大的灵活性,尤其是在需要重新配置或更换依赖的场景中。

 2.2.1 如何使用设置器注入

        在Spring中使用设置器注入非常简单。首先,你需要在你的类中提供一个公开的设置方法,然后使用@Autowired注解标注这个方法。Spring容器在创建这个类的Bean时,会自动调用这个设置方法,将相应的依赖注入进去。

2.2.2 示例代码

        假设你有一个ProductService类,它依赖于一个名为InventoryService的服务。下面是如何通过设置器注入来注入这个依赖:

        

@Component
public class ProductService {
    private InventoryService inventoryService;

    // 使用@Autowired注解标注设置方法
    @Autowired
    public void setInventoryService(InventoryService inventoryService) {
        this.inventoryService = inventoryService;
    }

    public void processProduct() {
        // 使用inventoryService进行一些操作
    }
}
2.2.3优势和使用场景

优势:

  • 灵活性:可以在对象的生命周期中的任何时点注入依赖,甚至可以重新注入不同的依赖。
  • 适合可选依赖:如果某个依赖是可选的,使用设置器注入可以避免在构造函数中处理复杂的逻辑。
  • 易于重新配置:适用于那些可能需要重新配置的组件。

使用场景:

  • 当依赖项可能在运行时改变时,例如基于某些业务规则更换策略对象。
  • 在需要通过配置来调整依赖关系的企业应用中,设置器注入提供了一种简单的方式来调整这些依赖。
  • 当某些依赖项是可选的,不是必需的,这时使用设置器注入可以避免在对象创建时就必须提供这些依赖。

潜在的缺点

  • 可能的不完整状态:如果在依赖注入之前就使用了对象,那么可能会导致运行时错误。
  • 过度使用可能导致代码混乱:如果一个类有很多通过设置器注入的依赖,这可能会使类变得难以管理和理解。
 2.3 字段注入

        定义:字段注入是最简单的注入方式,直接在需要的字段上标注@Autowired。这个也是我们最常见的使用,不过现在如果使用的是新的版本的话,idea更支持的是构造器注入了

代码示例

@Component
public class ProductService {
    @Autowired
    private InventoryService inventoryService;
}

优点

  • 写法简单,减少了样板代码。

缺点

  • 测试困难,因为没有公开的方法可以用来替换依赖。
  • 可能导致代码难以追踪,特别是在存在多个依赖的情况下。
2.4 方法注入
2.4.1 方法注入的概念

        方法注入主要用于当一个单例Bean需要引用一个原型Bean的实例时。由于单例Bean在Spring容器的生命周期内只创建一次,其依赖的原型Bean也只会注入一次。这就导致了单例Bean不能再次获取原型Bean的新实例,除非使用方法注入。

        Spring提供了一种方法注入的机制来解决这个问题。它主要通过两种方式实现:

  1. 查找方法注入:使用@Lookup注解来标注一个方法,这告诉Spring每次调用这个方法时都要在容器中查找并返回新的Bean实例。
  2. 方法替换:使用replaced-method元素来动态替换方法的实现。
2.4.2 找方法注入
@Component
public abstract class ProductService {

    public void processProduct() {
        PricingService pricingService = createPricingService();
        // 对pricingService执行一些操作
    }

    @Lookup
    protected abstract PricingService createPricingService();
}

        这里的 @Lookup 注解标注在 createPricingService() 方法上。Spring在运行时将动态生成 ProductService 的一个子类,并覆盖这个方法以从Spring容器中返回PricingService的新实例。

2.4.3 @Lookup 注解的作用

   @Lookup注解告诉Spring容器在每次调用该方法时,都应从Spring IoC容器中获取指定Bean的新实例。这对于处理原型依赖于单例Bean的情况非常有用。

2.4.4 结论和最佳实践

        方法注入特别适合于需要将设计模式如工厂方法模式整合到Spring管理的Bean中的场景。虽然方法注入在某些特定场景下非常有用,但应当谨慎使用,因为它增加了配置的复杂性并可能对性能产生影响。

2.5 总结

       尽管字段注入在某些情况下看似方便,但从长远来看,它可能会引入多种问题,特别是在大型项目中。  构造器注入是推荐的方式,特别是对于必需依赖,因为它能够确保依赖在使用前被正确设置。这也是最符合依赖注入原理的方法,因为它支持不可变性并且确保了对象始终处于有效状态。

3.Spring事务管理概述

         Spring的事务管理支持提供了一致的编程模型,既适用于声明式事务管理也适用于编程式事务管理。它与底层的事务基础设施进行了良好的抽象,使得开发者可以不用关心具体的事务管理API,就能实现跨不同事务管理API的事务操作。

3.1 声明式事务管理

        声明式事务管理是Spring推荐的事务管理方式。它将事务管理代码从业务代码中分离出来,通过配置方式来管理事务。这种方式使用@Transactional注解,非常简单而且高效。

3.1.1 使用@Transactional注解

        在Spring中,你可以通过在类或方法上添加@Transactional注解来声明一个事务。这个注解可以告诉Spring哪些方法是事务性的,以及这些事务应该如何被管理。

@Service
public class ProductService {
    @Transactional
    public void updateProductStock(Long productId, int newStock) {
        // 业务逻辑代码,例如更新库存
        // 这个方法中的所有数据库操作都会在同一个事务中执行
    }
}
3.1.2 @Transactional注解的参数解释
  1. propagation:定义了事务的传播行为。这决定了事务方法是如何相互作用的。例如,Propagation.REQUIRED表示当前方法必须在一个具有事务的上下文中执行,如果当前没有事务上下文,就会启动一个新的事务。

  2. isolation:定义了事务的隔离级别,这是一个关键设置,因为它防止了多个事务同时执行时可能产生的问题,如脏读、不可重复读和幻读。常用的隔离级别包括 READ_COMMITTEDREPEATABLE_READ 等。

  3. timeout:定义了事务在被回滚前可以运行的时间(秒)。如果事务超过这个时间还没有完成,就会自动回滚。这有助于防止长时间运行的事务占用资源。

  4. readOnly:标记事务是否为只读事务。设置为true可以帮助数据库优化事务。对于只查询数据的事务,设置为只读可以提高性能。

  5. rollbackFor:定义了哪些异常类会触发事务回滚。默认情况下,事务只对RuntimeExceptionError进行回滚。如果业务逻辑中检测到其他异常也需要回滚事务,需要显式设置。

  6. noRollbackFor:定义了哪些异常类不会触发事务回滚。这在特定情况下非常有用,比如当某些异常不应该导致事务失败时。

3.1.3 Spring Data JPA 和事务

        `Spring Data JPA简化了基于JPA的数据访问层的开发。事务管理是这一模块的核心组成部分,因为任何JPA操作几乎都需要在事务的上下文中执行。

事务的关键应用:

  • Repository层事务Spring Data JPA的Repository接口默认就支持声明式事务。通常不需要手动配置,但可以通过@Transactional注解自定义事务行为。这里很需要注意
  • 复杂查询:对于执行复杂的数据操作或查询,合适的事务管理确保了在执行过程中数据的一致性和完整性。
3.2 事务传播行为

        事务传播行为定义了一个事务性方法如何相对于调用它的方法事务进行交互。Spring定义了几种传播行为,以下是最常用的几种:

  1. REQUIRED(默认): 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  2. REQUIRES_NEW: 创建一个新事务,如果当前存在事务,则暂停当前事务。
  3. SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
  4. NOT_SUPPORTED: 以非事务方式执行操作,如果当前存在事务,则暂停当前事务。
  5. MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  6. NEVER: 以非事务方式执行,如果当前存在事务,则抛出异常。
  7. NESTED: 如果当前存在事务,则执行一个嵌套的子事务;如果当前没有事务,则表现如REQUIRED
3.3事务失效的场景

        Spring事务管理虽然强大,但在某些情况下可能会失效,导致事务不生效。以下是一些常见的场景:

  1. 私有方法调用:在同一个类中,一个非事务性的公共方法内部调用了一个标注为@Transactional的私有方法,事务是不会生效的,因为Spring事务是通过代理实现的,只能应用于公共接口方法。

  2. 自调用问题:一个类中的一个方法调用另一个标注为@Transactional的方法,如果是通过this方法调用的,事务是不会启动的,因为事务的开启需要通过代理对象来实现。

  3. 异常类型不正确@Transactional注解中可以指定一个异常类型,事务只有在抛出指定异常时才会回滚。如果抛出的异常类型不是事务注解中配置的回滚异常,事务也不会回滚。

  4. 数据库支持不足:如果数据库或数据库驱动不支持事务或当前隔离级别,那么标注了@Transactional的方法也无法正确管理事务。

  5. 方法是非公开的:如前所述,由于Spring的事务管理是通过AOP代理实现的,只有目标方法是公开的接口方法时,代理才能管理其事务。

4.总结

        依赖注入是Spring框架中一个核心的功能,它不仅提高了代码的可维护性和灵活性,还极大地简化了企业级应用的开发。理解和正确使用DI可以帮助开发者构建出更加健壮、可测试且易于维护的Java应用程序。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

5个方便好用的Python自动化脚本

相比大家都听过自动化生产线、自动化办公等词汇,在没有人工干预的情况下,机器可以自己完成各项任务,这大大提升了工作效率。 编程世界里有各种各样的自动化脚本,来完成不同的任务。 尤其Python非常适合编写自动化脚本&#xff0…

【JAVA】PO、VO、DAO、BO、DTO、POJO你分得清吗?

在Java开发中,PO、VO、DAO、BO、DTO、POJO这些词汇是比较常见的,每个术语都有其特定的含义和用途。下面是它们的具体区别: 名称简要概况用途和特定PO (Persistence Object) 持…

c++11详解

目录 1.列表初始化 2.声明 3.右值引用和移动语句 4. c11新的类功能 5. 可变参数模板 6.lambda表达式 7.包装器 8. 后言 1. 列表初始化 1.1 {}的初始化 (1) c98标准规定可以使用{}对数组以及结构体进行统一的列表初始化. struct Point {int _x;int _y; };int main() {in…

OpenStack的基本操作

1.实例类型管理 首先用管理员账号登录OpenStack 点击创建实例类型后:可以看见实例类型创建成功 2.项目与租户管理 Openstack有严格的项目及租户管理制度,在项目中使用管理员创建项目,然后为该项目创建一个以你姓名命名的账户为该项目的管理…

N5245B PNA-X 微波网络分析仪

N5245B PNA-X 微波网络分析仪 " 900 Hz/10 MHz 至 50 GHz " N5245B PNA-X 微波网络分析仪,900 Hz/10 MHz 至 50 GHz,2 端口和 4 端口,多达三个信号源。 特点 实现卓越性能 这款 PNA-X 分析仪不仅仅是一款矢量网络分析仪&a…

每日两题 / 46. 全排列 41. 缺失的第一个正数(LeetCode热题100)

46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 经典回溯题&#xff0c;每次搜索选择未选择数字中的一个 当选择了n个数时&#xff0c;将已经选择的数加入答案 class Solution { public:vector<vector<int>> permute(vector<int>& nums) {vector…

进制转换问题

1.十进制转二进制&#xff08;善于使用__int128&#xff09; 3373. 进制转换 - AcWing题库 #include<bits/stdc.h> using namespace std; __int128 x; int x_; string s1; int main(){stack<int> s;while(cin>>s1){int lens1.size();for(int i0;i<len;i)…

短视频素材怎么做?视频素材库那个好?

在这个视频内容占据主导的时代&#xff0c;高质量的无水印视频素材不仅能够丰富视觉体验&#xff0c;还能显著提升你的作品吸引力。为了帮助你在广阔的创意海洋中航行&#xff0c;下面介绍的一系列视频素材网站将为你的项目注入新的活力&#xff0c;让每个创意的火花都能闪耀发…

react之初识state

第二章 - 添加交互 State: 组件的记忆 组件通常需要根据交互更改屏幕上显示的内容。输入表单应该更新输入字段&#xff0c;单击轮播图上的“下一个”应该更改显示的图片&#xff0c;单击“购买”应该将商品放入购物车。组件需要“记住”某些东西&#xff1a;当前输入值、当前…

Multitouch 1.27.28 免激活版 mac电脑多点触控手势增强工具

Multitouch 应用程序可让您将自定义操作绑定到特定的魔术触控板或鼠标手势。例如&#xff0c;三指单击可以执行粘贴。通过执行键盘快捷键、控制浏览器的选项卡、单击鼠标中键等来改进您的工作流程。 Multitouch 1.27.28 免激活版下载 强大的手势引擎 精心打造的触控板和 Magic …

怎么办xgp会员一年多少钱xgp会员怎么开轻松教你xgp会员开通教程

怎么办&#xff1f;xgp会员一年多少钱&#xff1f;xgp会员怎么开&#xff1f;轻松教你xgp会员开通教程 XGP平台是由微软公司开发的xbox游戏平台的pc版本&#xff0c;为电脑玩家提供了一个游玩微软游戏的平台&#xff0c;XGP平台因其独特的会员服务而广受玩家们好评&#xff0…

浓眉大眼的Apple开源OpenELM模型;IDM-VTON试衣抱抱脸免费使用;先进的语音技术,能够轻松克隆任何人的声音

✨ 1: openelm OpenELM是苹果机器学习研究团队发布的高效开源语言模型家族 OpenELM是苹果机器学习研究团队开发的一种高效的语言模型&#xff0c;旨在推动开放研究、确保结果的可信赖性、允许对数据和模型偏见以及潜在风险进行调查。其特色在于采用了一种分层缩放策略&#x…

融合公式调权思考

一般在多目标任务任务中有加法公式、乘法公式、混合加法、非线性公式等&#xff0c;通过业务特性和应用场景选择不同方式&#xff0c;线上调参也有很多方案&#xff0c;自动寻参&#xff08;成本较高&#xff0c;比如进化算法、网格搜索、随机搜索、贝叶斯优化、自动调参工具如…

开发板通过网线连接电脑而上网

简介 关闭win11的防火墙&#xff08;之前不关也可以的&#xff0c;很奇怪&#xff09; 一句话&#xff1a;&#xff01;&#xff01;&#xff01;dhcp能自动分配IP即可联通外网&#xff01;&#xff01;&#xff01; 原理也不懂&#xff0c;或许有其他方法也不清楚&#xff0c…

采用php vue2 开发的一套医院安全(不良)事件管理系统源码(可自动生成鱼骨图)

采用php vue2 开发的一套医院安全&#xff08;不良&#xff09;事件管理系统源码&#xff08;可自动生成鱼骨图&#xff09; 医院安全&#xff08;不良&#xff09;事件管理系统采用无责的、自愿的填报不良事件方式&#xff0c;有效地减轻医护人员的思想压力&#xff0c;以事件…

项目上线流程(保姆级教学)

01&#xff1a;注册阿里云账户 02&#xff1a;登录阿里云 03&#xff1a;在桌面新建记事本保存个人账号密码等信息 04&#xff1a;完成重置密码 05&#xff1a;安装宝塔面板 命令行 yum install -y wget && wget -O install.sh http://download.bt.cn/install/instal…

Maya vs Blender:制作3D动画首选哪一个?

就 3D 动画而言&#xff0c;有两款3D软件引发了最多的争论&#xff1a;Blender 与 Maya。这两个强大的平台都提供强大的工具集&#xff0c;使动画故事和角色栩栩如生。但作为一名3D动画师&#xff0c;您应该投入时间学习和创作哪一个呢&#xff1f;下面我将从以下六点给您一个清…

spring boot中的标注@Component、@Service等

让我告诉你什么叫水货。 一、水货横行 一直以来&#xff0c;我对Spring Boot项目中的标注&#xff0c;像Component啦、Service啦、Configuration啦&#xff0c;甚至Autowired啦&#xff0c;等等&#xff0c;都似懂非懂。Autowired与Resource有什么区别也不清楚。 个中原因&a…

分享:抖音阳哥说的人力RPO项目有哪些优势?

在数字化浪潮的推动下&#xff0c;人力资源行业也迎来了前所未有的变革。抖音平台上&#xff0c;阳哥以其独到的见解和丰富的经验&#xff0c;对人力RPO(招聘流程外包)项目进行了深入解读。今天&#xff0c;我们就来探讨一下人力RPO项目究竟有哪些优势。 人力RPO项目的一大优势…

get和post的区别?get不安全-post安全|面试官:好,你走吧

get和post的区别&#xff1f;get不安全-post安全|面试官&#xff1a;好&#xff0c;你走吧 开个小玩笑&#xff0c;面试官肯定是想知道更详细的内容&#xff0c;那面下面就是相对详细的内容&#xff0c;请收下吧(*&#xffe3;︶&#xffe3;) 1、url可见性 get&#xff0c;参…