当前位置: 首页 > article >正文

基于Spring框架的分层解耦详解

  • 博客主页:誓则盟约
  • 系列专栏:Java Web
  • 关注博主,后期持续更新系列文章
  • 如果有错误感谢请大家批评指出,及时修改
  • 感谢大家点赞👍收藏⭐评论✍ 

Java Web 三层架构:

Java Web可以大致被分为三层架构:

  • controller:控制层
  • service:业务逻辑层
  • dao:数据访问层

Controller层:

        controller层也称为控制层,只要功能是接收前端发送的请求,对请求进行处理,并响应数据。

        作为应用程序的入口点之一,Controller 层负责接收来自客户端(如浏览器、移动设备等)的 HTTP 请求。这些请求可以是 GET、POST、PUT、DELETE 等不同类型的请求,例如,在 Web 应用中,当用户在浏览器中输入一个 URL 或者提交一个表单时,请求会被发送到相应的 Controller。

        它会解析请求中的参数,如查询字符串参数(对于 GET 请求)或者表单数据(对于 POST 请求)。例如,在一个登录功能中,Controller 会获取用户输入的用户名和密码参数。

注:Controller 层并不直接实现业务逻辑,而是调用 Service 层(业务逻辑层)的方法来处理业务。

Service层:

        service层也称为业务逻辑层,在 Java 应用架构(特别是遵循 MVC 或类似分层架构的应用)中,Service 层(业务逻辑层)扮演着核心的角色,其中主要是处理具体的业务逻辑。

        Service 层包含了应用的复杂且核心的业务逻辑。例如,在一个银行系统中,转账业务逻辑就会在 Service 层实现。它需要考虑诸如账户余额检查、转账金额的合法性、更新相关账户余额等操作。

        除此之外,Service通常还负责管理事务。在涉及多个数据库操作的业务场景中,如订单处理(包括创建订单、扣减库存、更新用户积分等多个数据库操作),Service 层确保这些操作要么全部成功(提交事务),要么全部失败(回滚事务)。

        在架构中Service 层为 Controller 层提供业务处理方法。Controller 层调用 Service 层的方法来完成具体的业务操作。

Dao层:

        Dao(Data Access Object)层也称为数据访问层,主要负责数据访问操作,包括数据的增删改查。

        Dao 层的主要目的是将数据库操作抽象出来,为上层(通常是 Service 层)提供统一的访问数据库的接口。这样,上层业务逻辑层不需要关心具体的数据库类型(如 MySQL、Oracle 等)以及数据库的底层操作细节(如 SQL 语句的编写、数据库连接的管理等)。例如,在一个企业级应用中,无论是使用关系型数据库还是非关系型数据库,Service 层只需要调用 Dao 层提供的方法(如findUserByIdsaveUser等)就可以实现对数据的操作。

        除此之外,Dao层还负责执行数据的持久化操作,包括将数据保存到数据库(插入操作)、从数据库中查询数据、更新数据库中的数据以及删除数据库中的数据等操作。因此,Dao层也被称为持久层。


分层解耦:

首先要知道内聚和耦合两个概念:

  • 内聚:软件中各个功能模块内部的功能联系。
  • 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。

         在开发过程中,我们要朝着高内聚低耦合的方向实施,最好可以让层与层之间解除耦合,让他们不产生依赖,这样我们程序的灵活性和可扩展性会更佳。

        下面我们以Spring框架为例讲解如何实现解耦操作。在 Spring 框架中,解耦主要通过控制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)的机制来实现。

控制反转(IOC):

        在没有使用 Spring 等框架进行解耦之前,对象之间的依赖关系通常是由对象自己创建和管理的。例如,在一个业务逻辑类中,如果需要调用数据访问层的方法来获取数据,它可能会直接实例化数据访问层的对象。

   public class BusinessLogicClass {
       public void doSomeBusinessLogic() {
           DataAccessClass dataAccess = new DataAccessClass();
           // 使用 dataAccess 对象进行数据操作
       }
   }

        这种方式存在的问题是,业务逻辑类与数据访问类紧密耦合,当数据访问层的实现发生变化时,业务逻辑类也需要进行相应的修改。

        而Spring 框架引入了控制反转的概念,即对象的创建和依赖关系的管理不再由对象自己负责,而是交给一个外部的容器(通常是 Spring 容器)来管理。而在IOC容器中创建、管理的对象,称之为bean

        这样在 Spring 中,对象只需要声明自己所需要的依赖,而不需要关心这些依赖是如何创建和初始化的。例如:

   public class BusinessLogicClass {
       private DataAccessInterface dataAccess;

       public BusinessLogicClass(DataAccessInterface dataAccess) {
           this.dataAccess = dataAccess;
       }

       public void doSomeBusinessLogic() {
           // 使用 dataAccess 对象进行数据操作
       }
   }

        这里,BusinessLogicClass不再自己创建DataAccessClass的实例,而是通过构造函数接收一个实现了DataAccessInterface接口的对象。这样,BusinessLogicClass只依赖于接口,而不依赖于具体的实现类,实现了解耦。

依赖注入(DI):

        容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。这些资源一般取自Spring容器中的bean对象。

        Spring 框架通过依赖注入的方式来实现控制反转。依赖注入有多种方式,常见的有构造函数注入、Setter 注入和字段注入。

        构造函数注入:在对象创建时,通过构造函数将依赖对象传递进去。例如上面的例子中,BusinessLogicClass通过构造函数接收DataAccessInterface的实现对象。

        Setter 注入:通过设置方法将依赖对象注入到对象中。

        字段注入:使用注解(如@Autowired)直接在字段上进行依赖注入。例如:

   import org.springframework.beans.factory.annotation.Autowired;

   public class BusinessLogicClass {
       @Autowired
       private DataAccessInterface dataAccess;

       public void doSomeBusinessLogic() {
           // 使用 dataAccess 对象进行数据操作
       }
   }

解耦的好处:

1.可维护性

        由于对象之间的依赖关系通过接口进行解耦,当一个模块的实现发生变化时,只需要修改对应的实现类,而不会影响到其他模块。例如,如果数据访问层的实现从使用一种数据库切换到另一种数据库,只需要修改数据访问层的实现类和 Spring 配置文件,业务逻辑层不需要做任何修改。

2.可测试性

        解耦后的代码更容易进行单元测试。在测试业务逻辑类时,可以通过注入模拟的依赖对象(如使用模拟框架创建的模拟数据访问对象)来隔离其他模块的影响,只专注于测试业务逻辑本身。

3.可扩展性

        当需要添加新的功能模块时,可以很容易地将新模块集成到系统中,只需要在 Spring 配置文件中定义新模块的 bean,并将其注入到需要的地方即可。例如,添加一个新的业务逻辑模块,只需要在配置文件中定义新的 bean,并将其注入到现有的业务逻辑类中,实现功能的扩展。


欲买桂花同载酒,终不似、少年游。—— 《唐多令·芦叶满汀洲》


http://www.kler.cn/a/324135.html

相关文章:

  • 算法魅力-二分查找实战
  • 五、函数封装及调用、参数及返回值、作用域、匿名函数、立即执行函数
  • uview Collapse折叠面板无法动态设置展开问题(微信小程序)
  • 【鸿蒙开发】第十一章 Stage模型应用组件-任务Mission
  • 前端学习八股资料CSS(二)
  • k8s 1.28.2 集群部署 docker registry 接入 MinIO 存储
  • node后端react前端简单实例
  • react hooks--useImperativeHandle
  • 洛谷 P10456 The Pilots Brothers‘ refrigerator
  • 基于php的民宿预订管理系统
  • pkg升级导致xfce虚拟终端无法启动甚至xfce挂死无法登入@FreeBSD(未解决)
  • vue3更具文件目录动态添加路由配置
  • django drf 统一Response格式
  • ES6的简单介绍(第二部分)
  • Unity与AI对话系统互动生成表情示例
  • linux的中断管理机制
  • Python实现Phong着色模型算法
  • sheng的学习笔记-AI-时序差分学习
  • Android——ContentObserver监听短信
  • Mysql高级篇(中)——锁机制
  • 前端测试最强教程 - 实现 fake http 和 fake db
  • [SAP ABAP] SELECT-OPTIONS
  • 线程池面试集
  • 「JavaScript深入」深拷贝与浅拷贝,如何手写实现?
  • npm下载淘宝镜像的方式和用法
  • 在一个.NET Core项目中使用RabbitMQ进行即时消息管理