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

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

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

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

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

java 复制代码
   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)直接在字段上进行依赖注入。例如:

java 复制代码
   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,并将其注入到现有的业务逻辑类中,实现功能的扩展。


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

相关推荐
神仙别闹10 分钟前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭34 分钟前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫1 小时前
泛型(2)
java
超爱吃士力架1 小时前
邀请逻辑
java·linux·后端
南宫生1 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石1 小时前
12/21java基础
java
李小白661 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp1 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶2 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb
n北斗2 小时前
常用类晨考day15
java