后端工程架构系列篇(一):单应用多模块(按业务拆分)

@

目录
,适合中小团队)

目录

简单聊聊

单体应用 VS 微服务,如何选?务必要根据公司开发人员数量和系统业务宽度来进行选择,如果你是为了简历好看或者学习,另当别论。微服务就是拆散了技术成熟的单体应用,然后又借助外部工具重新把他们粘起来,如通信、事务、部署、日志等,下一篇就会涉及,到时候我们就用阿里工具箱来演示,如dubbo、nacos、seata等。。本期介绍一个折中的选择,单应用多模块架构方式,后期想做微服务也会非常方便,无需推翻。

适用对象

绝大多数公司采用单应用多模块架构来开发足矣

  1. 中小团队(百人以内)
  2. 高内聚系统
  3. 分组分模块开发

正式开始

环境组件:以springboot2+hibernate为基础,java:11,开发工具:idea,数据库:mysql5
演示业务:创建订单(公共接口)->扣除商品库存(公共接口)->增加商品销量(私有接口),如果库存不足就进行事务回滚。订单和商品是2个模块。包含service级的基础校验@Validated

  1. 完整的项目工程结构
    后端工程架构系列篇(一):单应用多模块(按业务拆分)

  2. 创建根项目
    根项目使用spring的脚手架,其他子模块就选择Maven
    后端工程架构系列篇(一):单应用多模块(按业务拆分)

后端工程架构系列篇(一):单应用多模块(按业务拆分)

  1. 创建common模块
    new->module后端工程架构系列篇(一):单应用多模块(按业务拆分)
    直接next
    后端工程架构系列篇(一):单应用多模块(按业务拆分)

后端工程架构系列篇(一):单应用多模块(按业务拆分)
common模块的结构,公共接口、公共出参、公共入参等
后端工程架构系列篇(一):单应用多模块(按业务拆分)

  1. 创建web模块
    new->module后端工程架构系列篇(一):单应用多模块(按业务拆分)
    直接next
    后端工程架构系列篇(一):单应用多模块(按业务拆分)
    后端工程架构系列篇(一):单应用多模块(按业务拆分)

web模块结构图,包含:控制器、过滤器、拦截器,配置文件yml,启动类等,以及权限校验、swagger文档等,类似网关的作用,后端工程架构系列篇(一):单应用多模块(按业务拆分)
注意:web模块为启动类,在pom.xml添加以下代码,可以在根项目里复制过来,并且需要把根项目这段代码去掉

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

这是OrderController类,可以一个服务对应一个controller

package com.mmyk.scli.web.controller;

import com.mmyk.scli.common.request.CreateOrderRequest;
import com.mmyk.scli.common.service.OrderCommonService;
import com.mmyk.scli.web.vo.ResponseVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@Tag(name = "订单")
@RestController
public class OrderController {

    @Autowired
    private OrderCommonService orderCommonService;

    @Operation(summary = "创建订单")
    @PostMapping("/order.create")
    public Object prod(@RequestBody CreateOrderRequest param) {
        return ResponseVO.ok(orderCommonService.createOrder(param));
    }
}

  1. 创建service模块
    new->module后端工程架构系列篇(一):单应用多模块(按业务拆分)
    直接next
    后端工程架构系列篇(一):单应用多模块(按业务拆分)
    后端工程架构系列篇(一):单应用多模块(按业务拆分)
    service模块结构图,作为所有业务模块的父模块
    后端工程架构系列篇(一):单应用多模块(按业务拆分)
    service模块下: 创建商品子模块,该模块可以建立自己的yml
    注意Parent,选择service模块
    后端工程架构系列篇(一):单应用多模块(按业务拆分)

后端工程架构系列篇(一):单应用多模块(按业务拆分)
该实现有2个接口,一个为common模块下公共接口,一个为本模块内的接口,第二个只供本模块内部使用。
后端工程架构系列篇(一):单应用多模块(按业务拆分)
这是订单子模块的 orderServiceImpl,创建订单

package com.mmyk.slic.service.order.service.impl;

import com.mmyk.scli.common.request.CreateOrderRequest;
import com.mmyk.scli.common.request.DeductStockRequest;
import com.mmyk.scli.common.response.CreateOrderResponse;
import com.mmyk.scli.common.response.DeductStockResponse;
import com.mmyk.scli.common.service.OrderCommonService;
import com.mmyk.scli.common.service.ProductCommonService;
import com.mmyk.slic.service.order.dao.OrderDao;
import com.mmyk.slic.service.order.entiy.Order;
import com.mmyk.slic.service.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

@Slf4j
@Validated
@Service
public class OrderServiceImpl implements OrderCommonService, OrderService {
    @Autowired
    private OrderDao orderDao;

    @Autowired
    private ProductCommonService productCommonService;

    @Transactional
    @Override
    public CreateOrderResponse createOrder(CreateOrderRequest request) {
        log.info("OrderServiceImpl.createOrder() ok");
        Long count = orderDao.count();
        log.info("当前order表总行数:{}", count);

        Order order = new Order();
        order.setOrderNumber("100001");
        order.setProductId(request.getProductId());
        order = orderDao.save(order);
        CreateOrderResponse createOrderResponse = new CreateOrderResponse();
        createOrderResponse.setOrderId(order.getOrderId());

        DeductStockRequest deductStockRequest = new DeductStockRequest();
        deductStockRequest.setProductId(request.getProductId());
        deductStockRequest.setQuantity(request.getQuantity());
        DeductStockResponse deductStockResponse = productCommonService.deductStock(deductStockRequest);

        return createOrderResponse;
    }
}

注意事项

  1. 业务模块之间是单向依赖,不能相互依赖。类似spring要求service不能相互引用。
  2. 启动类要加上各类bean的扫描
  3. A子模块调用B子模块,需要A在本模块的pom.xml内再引入B,后期如果微服务化,如基于rpc调用就无需引入,只用在service模块引入common模块即可
  4. web模块pom.xml增加启动类配置,去掉根项目pom.xml启动配置

源代码

gitee

下一篇:后端工程架构系列篇(二):微服务

基于阿里工具箱,dubbo、nacos、seata,全部为当前最新版本来演示

上一篇:vue中全局公共方法的使用


下一篇:Wix打包系列(五) 部署数据库