You need to enable JavaScript to run this app. Spring Boot服务层控制器层解耦设计模式最佳实践 聚合服务优化
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot服务层控制器层解耦设计模式最佳实践 聚合服务优化

持续向MyLastService注入更多依赖的实际问题
  • 违反单一职责原则:这个类既要维护越来越多的依赖装配关系,又要承载订单创建的流程编排,后续每新增一个下游依赖,都要修改这个类,哪怕业务流程本身没有调整,也会额外增加无意义的代码改动量。
  • 单元测试成本飙升:测试这个类的逻辑时,需要Mock所有注入的依赖,依赖数量超过5个之后,Mock配置代码的长度往往会超过核心业务逻辑的长度,后续修改测试用例的维护成本会越来越高。
  • 代码耦合度失控:所有下游服务的接口调整都会直接改动这个类,比如UserService的查询方法参数变了,哪怕只是一个分支逻辑用到,也要动MyLastService的代码,类的稳定性会越来越差,改一个地方牵一发动全身。
  • 核心逻辑被稀释:字段声明、重复的try-catch代码越堆越多,后续维护的人打开类之后,要翻几十行依赖声明、异常处理代码才能找到核心的业务流程,可读性直线下降。
新增分层的落地设计方法
  • 先明确拆分边界:把原来MyLastService里的跨服务编排职责从基础领域服务中剥离,不要把所有调用逻辑都堆在一个实现类里。
  • 三层职责划清楚:
    • 原子领域服务层:就是当前的ProductService、OrderService、UserService这类,每个服务只负责自己领域内的原子操作,比如商品服务只管商品的增删改查,不注入其他领域的服务,不写跨域的流程逻辑。
    • 应用编排层:这层的唯一作用就是对着具体的业务用例,调用下层的原子服务串起完整流程,不实现具体的领域规则,也不直接对接数据库或第三方接口。
    • 控制器层:只负责接请求、做参数校验、调用编排层的接口返回结果,不写任何业务逻辑代码。
  • 不要搞“大而全”的服务类:拆分时把每个独立业务用例对应成独立的编排类,不要把所有用例的调用都塞在同一个MyLastService里,比如“新增订单”对应CreateOrder类,“查询订单详情”对应QueryOrder类,每个类只注入自己需要的依赖。
适配场景的设计模式与SpringBoot最佳实践
  • 核心适配的设计模式:
    • 门面模式(Facade):把多个下游服务的调用、顺序、参数组装逻辑封装在统一的编排入口里,上层调用方(比如控制器)不需要知道内部要调哪几个服务、调用顺序是什么,只需要调用编排层的统一方法即可,完全匹配当前跨服务调用的场景。
    • 用例拆分模式:每一个独立业务场景单独拆成一个类,每个类只负责当前场景的逻辑,只注入当前场景需要的依赖,从根源上避免单类依赖过多的问题。
  • Spring Boot下的具体落地规则:
    • 把原来的字段@Autowired注入改成构造器注入,当类的依赖数量过多时,构造器的参数会变长,从编码层面就能直观感知到类已经膨胀了,需要拆分;而且构造器注入写单元测试的时候不需要用反射注入Mock对象,测试写起来更简单。
      举个调整后的代码示例:
      @Service
      public class CreateOrderService {
          private static final Logger LOGGER = LoggerFactory.getLogger(CreateOrderService.class);
          // 只注入当前业务场景需要的服务
          private final ProductService productService;
          private final UserService userService;
          private final ReferentialService referentialService;
          private final OrderService orderService;
      
          // 构造器注入,Spring自动完成依赖装配
          public CreateOrderService(ProductService productService,
                                   UserService userService,
                                   ReferentialService referentialService,
                                   OrderService orderService) {
              this.productService = productService;
              this.userService = userService;
              this.referentialService = referentialService;
              this.orderService = orderService;
          }
      
          public void addNewOrder(MyRequest req) {
              try {
                  Product p = productService.findProduct(req.getProductId());
                  User u = userService.findUserByUserName(req.getUserName());
                  City c = referentialService.findCity(req.getCity());
                  orderService.addOrder(p, u, c);
              } catch (Exception e) {
                  LOGGER.error("error : {}", e.getMessage());
              }
          }
      }
      
    • 服务层和控制器层解耦的通用规则:
      • 控制器不要直接调用原子领域服务,所有跨服务的业务逻辑都要经过编排层,避免控制器层堆业务代码,后续逻辑调整时还要改动控制器。
      • 编排层不要直接操作数据库、不要直接调用第三方接口,所有资源访问逻辑都下沉到最底层的原子服务中,保证编排层只做流程判断、参数组装,不承载具体实现细节。
      • 重复的try-catch逻辑不要散落在每个业务方法里,用Spring的@RestControllerAdvice做全局异常拦截,把通用的异常处理逻辑统一处理,减少业务方法里的冗余代码。

内容的提问来源于stack exchange,提问作者A.khalifa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.05 07:57:02