【若依】Spring Boot 分层架构,为什么这么设计,以及执行过程


一、为什么是分层架构设计?

后端采用分层架构设计(如常见的 Controller → Service → Mapper/DAO)并不是为了“多写几层代码”,而是为了解决软件系统在规模增长过程中的复杂性管理、可维护性、可扩展性和团队协作等核心问题。

🧱 什么是分层架构?

分层架构(Layered Architecture)是一种将系统按职责划分为多个逻辑层的设计模式。在 Java 后端开发中,最常见的分层是:

Controller(控制层)
   ↓
Service(业务逻辑层)
   ↓
Mapper / DAO(数据访问层)

每一层都有明确的职责,上层依赖下层,但不能反向依赖


✅ 核心原因:职责分离(Separation of Concerns)

让每个模块只做一件事,并把它做好。

  • Controller:只负责处理 HTTP 请求和响应(参数解析、返回格式封装)。
  • Service:只负责业务逻辑(比如“用户下单”涉及库存扣减、订单创建、积分增加等)。
  • Mapper/DAO:只负责与数据库交互(增删改查)。

📌 好处:代码清晰、易于理解和维护。


✅ 提高可维护性(Maintainability)

假设没有分层,所有逻辑都写在 Controller 中:

@GetMapping("/order")
public Result createOrder() {
    // 1. 参数校验
    // 2. 查询用户信息
    // 3. 扣减库存
    // 4. 创建订单
    // 5. 发送消息
    // 6. 记录日志
    // ... 几百行代码混在一起
}

一旦需求变更(比如加个优惠券逻辑),你就得在这个“大方法”里改,极易出错。

而有了分层后:

// Controller 很干净
public Result createOrder() {
    return orderService.createOrder(userId, productId);
}

// Service 层处理复杂逻辑
public void createOrder(Long userId, Long productId) {
    validateUser(userId);
    reduceStock(productId);
    createOrderRecord();
    sendNotification();
}

📌 修改某个功能时,只需定位到对应层的类即可,不影响其他部分。


✅ 提升可测试性(Testability)

分层后可以对每一层进行独立测试:

  • 单元测试(Unit Test):Mock Mapper,测试 Service 是否正确调用。
  • 集成测试(Integration Test):测试 Controller 是否能正确返回 JSON。
  • 数据库测试:单独测试 Mapper 的 SQL 是否正确执行。

如果没有分层,测试一个包含数据库操作、业务逻辑、HTTP 处理的“大方法”,几乎是不可能的。


✅ 支持复用(Reusability)

同一个 Service 方法可以被多个 Controller 调用。

例如:

  • Web 端下单 → 调用 orderService.createOrder()
  • App 端下单 → 同样调用 orderService.createOrder()
  • 定时任务补单 → 还是调用它

📌 业务逻辑只需写一遍,避免重复代码(DRY 原则)


✅ 便于团队协作

大型项目通常由多人协作开发:

  • 前端工程师关注 API 接口(Controller 层)
  • 业务开发工程师专注核心逻辑(Service 层)
  • 数据库工程师优化 SQL(Mapper 层)

分层后,每个人可以专注于自己的模块,通过接口约定进行协作,减少冲突。


✅ 支持横切关注点(Cross-Cutting Concerns)

事务管理、日志记录、权限校验、缓存 等功能,通常作用于多个方法或类。

分层架构让这些功能更容易通过 AOP(面向切面编程)统一处理:

@Transactional  // 作用于 Service 方法,保证事务一致性
public void transferMoney(A***ount from, A***ount to, BigDecimal amount) {
    a***ountMapper.debit(from, amount);
    a***ountMapper.credit(to, amount);
}

📌 如果业务逻辑散落在 Controller 中,就很难统一加事务。


✅ 增强可扩展性(Scalability)

当系统需要扩展时,分层架构更容易应对变化:

需求 分层架构如何应对
更换数据库 只需重写 Mapper 层,Service 不变
引入缓存 在 Service 层加 @Cacheable,不影响 Controller
拆分为微服务 可以将 Service 打包为独立服务供多个系统调用

❌ 如果不加分层?会怎样?

问题 描述
代码臃肿 所有逻辑堆在 Controller,难以阅读
重复代码多 相同逻辑在多个接口中复制粘贴
难以测试 无法单独测试业务逻辑
耦合严重 改一个地方,其他功能全崩
团队协作难 多人修改同一个文件,频繁冲突

这就是所谓的“大泥球架构”(Big Ball of Mud),是软件设计的大忌。


🎯 总结:分层架构的核心价值

价值 说明
✅ 职责清晰 每层各司其职,代码结构清晰
✅ 易于维护 修改一处不影响全局
✅ 可测试性强 支持单元测试、Mock 测试
✅ 可复用 Service 可被多处调用
✅ 易于协作 团队分工明确
✅ 支持 AOP 事务、日志、缓存统一处理
✅ 便于演进 未来可轻松升级或拆分

💬 最后一句话

分层不是为了“多写代码”,而是为了让系统“活得更久、跑得更稳”。

就像盖房子要打地基、分楼层一样,软件系统也需要合理的结构设计。分层架构,就是后端开发中最基础、最有效的“建筑蓝图”。


📌 建议:即使是小项目,也建议使用标准分层结构。良好的习惯,从第一天开始养成。

如果你正在学习 Spring Boot 或准备面试,理解分层架构的思想远比记住“Controller → Service → Mapper”这个顺序更重要。

二、分层架构的一般结构

当然可以。以下是关于分层架构(Layered Architecture) 的详细介绍,针对后端开发中最常见的结构进行拆解,帮助你全面理解每一层的职责、协作方式以及典型实现。


🏗️ 分层架构的结构详解:后端系统的“建筑蓝图”

在软件工程中,分层架构(Layered Architecture)是最经典、最广泛使用的系统设计模式之一。它通过将系统划分为多个逻辑层级,实现关注点分离(Separation of Concerns),从而提升代码的可维护性、可测试性和可扩展性。

在 Java 后端开发中(尤其是基于 Spring Boot + MyBatis 的项目),最常见的分层结构是 “四层架构”

┌─────────────────┐
│   Controller    │  ← HTTP 请求入口
├─────────────────┤
│     Service     │  ← 业务逻辑核心
├─────────────────┤
│     Mapper      │  ← 数据库操作
├─────────────────┤
│    Domain/POJO  │  ← 数据载体
└─────────────────┘

下面我们逐层解析其结构与职责。


Controller 层:控制层(Web 层)

📍 职责

  • 接收 HTTP 请求(GET、POST 等)
  • 解析请求参数(如 JSON、表单、路径变量)
  • 调用 Service 层处理业务
  • 封装并返回响应结果(通常是 JSON 格式)

📁 位置

src/main/java/***/your***pany/project/controller/

✅ 示例代码

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public Result<UserVO> getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        return Result.su***ess(UserVO.from(user));
    }
}

🔑 关键点

  • 使用 @RestController@Controller
  • 不包含复杂业务逻辑
  • 负责统一返回格式(如封装 Result.su***ess(data)
  • 可进行参数校验(如 @Valid

Service 层:业务逻辑层

📍 职责

  • 实现核心业务逻辑(如“下单”、“支付”、“审核”)
  • 协调多个数据操作(如先扣库存,再创建订单)
  • 处理事务(@Transactional
  • 调用 Mapper 层进行数据访问
  • 可集成缓存、消息队列、远程调用等

📁 位置

src/main/java/***/your***pany/project/service/IUserService.java
src/main/java/***/your***pany/project/service/impl/UserServiceImpl.java

✅ 接口定义(IUserService.java)

public interface IUserService {
    User findById(Long id);
    void createUser(User user);
}

✅ 实现类(UserServiceImpl.java)

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    @Transactional
    public void createUser(User user) {
        // 业务逻辑:校验、默认值设置等
        user.setCreateTime(new Date());
        userMapper.insert(user);
    }
}

🔑 关键点

  • 是系统的“大脑”,承载核心逻辑
  • 方法应具备原子性可复用性
  • 使用 @Service 注解
  • 接口与实现分离,便于扩展和测试

Mapper 层:数据访问层(DAO 层)

📍 职责

  • 与数据库直接交互
  • 执行 SQL 语句(增删改查)
  • 将数据库记录映射为 Java 对象(ORM)
  • 通常由 MyBatis 或 JPA 实现

📁 位置

src/main/java/***/your***pany/project/mapper/UserMapper.java
src/main/resources/mapper/UserMapper.xml

✅ Mapper 接口

public interface UserMapper {
    User selectById(Long id);
    void insert(User user);
    List<User> selectAll();
}

✅ XML 映射文件(UserMapper.xml)

<mapper namespace="***.your***pany.project.mapper.UserMapper">
    <select id="selectById" resultType="User">
        SELECT * FROM users WHERE id = #{id}
    </select>
    
    <insert id="insert">
        INSERT INTO users (name, email, create_time)
        VALUES (#{name}, #{email}, #{createTime})
    </insert>
</mapper>

🔑 关键点

  • 只负责“数据搬运”,不处理业务逻辑
  • SQL 与 Java 代码解耦(XML 方式更清晰)
  • 可使用 MyBatis-Plus 简化 CRUD 操作

Domain 层:领域模型层(实体层)

📍 职责

  • 定义数据结构,映射数据库表
  • 作为各层之间数据传递的载体
  • 通常包含 getter/setter、构造方法等

📁 位置

src/main/java/***/your***pany/project/domain/User.java

✅ 示例

public class User {
    private Long id;
    private String name;
    private String email;
    private Date createTime;

    // getter, setter...
}

🔑 常见变体

类型 说明
PO (Persistent Object) 持久化对象,与数据库表一一对应
VO (View Object) 视图对象,用于返回给前端的数据结构
DTO (Data Transfer Object) 数据传输对象,用于跨层或跨服务传输
BO (Business Object) 业务对象,封装特定业务场景的数据

🔄 各层之间的调用关系

HTTP Request
     ↓
[Controller] → 调用 → [Service Interface]
                     ↗
           [Service Impl] → 调用 → [Mapper]
                     ↖           ↗
                      [Domain 实体类]
  • Controller 注入 Service 接口
  • ServiceImpl 注入 Mapper
  • Mapper 操作 Domain 实体
  • 所有数据通过 Domain 类在层间传递

🧩 可选扩展层(中大型项目常见)

层级 说明
Manager 层 介于 Service 和 Mapper 之间,用于封装通用数据操作逻辑
Facade 层 对外提供统一接口,隐藏内部复杂性(常用于微服务)
Util 工具层 存放通用工具类(如日期、加密、文件处理)

✅ 分层架构的优点总结

优点 说明
职责清晰 每层只做一件事,代码结构清晰
易于维护 修改某层不影响其他层
便于测试 可对 Service 层进行 Mock 测试
支持复用 Service 可被多个 Controller 调用
易于协作 团队成员可并行开发不同层
支持 AOP 事务、日志、缓存可统一处理

❌ 注意事项

  • ❌ 不要将业务逻辑写在 Controller 或 Mapper 中
  • ❌ 不要让 Controller 直接调用 Mapper(破坏分层)
  • ✅ 建议使用接口定义 Service,便于扩展和测试
  • ✅ 保持层与层之间的单向依赖,避免循环引用

🏁 结语

分层架构就像一栋大楼的结构:地基(Mapper)、主体(Service)、门窗(Controller)、内部装修(Domain),每一部分各司其职,共同构成一个稳定、可扩展的系统。

掌握这种结构,不仅是写代码的规范,更是软件设计思维的体现。无论你是初学者还是资深开发者,理解并实践分层架构,都将极大提升你的工程能力。

好的架构,不是为了复杂,而是为了让系统更简单地应对复杂。

三、项目中分层结构图

四、后端分层代码执行过程

XXXController

I XXX Service

XXXServiceImpl


XXXMapper

XXXMapper.xml

转载请说明出处内容投诉
CSS教程网 » 【若依】Spring Boot 分层架构,为什么这么设计,以及执行过程

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买