微服务架构设计笔记 微服务架构设计笔记从 Spring Boot 单体到 Spring Cloud Alibaba 微服务体系一份通用的架构实战指南。一、目录结构总览project/ │ ├── pom.xml # 父 POM统一版本管理、模块聚合 │ ├── project-framework/ # 【框架层】项目基础设施 │ ├── pom.xml │ ├── project-common-core/ # 公共核心统一响应、枚举基类、基础工具 │ ├── project-common-security/ # 安全模块JWT 工具、加密工具、权限注解 │ ├── project-common-redis/ # 缓存模块Redis 配置、分布式锁 │ └── project-api/ # Feign 接口层所有服务间远程调用接口 │ ├── project-user-api/ # 用户服务 Feign 接口 │ ├── project-order-api/ # 订单服务 Feign 接口 │ └── project-commodity-api/ # 商品服务 Feign 接口 │ ├── project-gateway/ # 【API 网关】统一入口、路由转发、鉴权、限流 │ ├── config/ # 跨域配置、路由配置 │ └── filter/ # JWT 鉴权过滤器、日志过滤器 │ ├── project-services/ # 【业务服务层】聚合 POM不写代码 │ ├── pom.xml │ ├── project-user/ :8082 # 用户服务 │ ├── project-order/ :8083 # 订单服务 │ ├── project-commodity/ :8084 # 商品服务 │ └── project-message/ :8085 # 消息服务 │ ├── project-job/ # 【定时任务】XXL-Job 执行器 └── docker-compose.yml # 本地开发环境二、为什么这样设计2.1 分层思想框架层framework ↓ 被依赖 业务服务层services ↑ 调用 API 层api── Feign ──→ 业务服务层 ↓ 网关层gateway── 路由 ──→ 业务服务层每一层职责清晰层职责能依赖谁framework提供基础能力只依赖第三方库api定义服务间契约依赖 frameworkservices业务逻辑实现依赖 framework apigateway流量入口依赖 framework2.2 对比单体架构单体架构项目/ ├── src/main/java/com/xxx/ │ ├── controller/ # 所有 Controller 混在一起 │ ├── service/ # 所有 Service 混在一起 │ ├── mapper/ # 所有 Mapper 混在一起 │ ├── entity/ # 所有实体类 │ └── utils/ # 所有工具类 └── pom.xml # 所有依赖问题改一行代码整个项目重新部署订单模块挂了用户模块也用不了所有 Service 可以互相注入耦合无法控制几十个人同时改一个项目Git 冲突不断微服务架构project/ ├── project-framework/ # 公共部分独立 ├── project-services/ │ ├── project-user/ # 独立部署 │ └── project-order/ # 独立部署 └── project-gateway/ # 统一入口好处改用户服务只重启用户服务订单服务挂了用户还能登录服务和服务的通信必须通过 Feign 接口能调什么、不能调什么一清二楚每个团队只维护自己的服务三、单体 → 微服务改造详解3.1 Controller 层改造改造前单体// 所有业务逻辑堆在 Controller 里RestControllerRequestMapping(/order)publicclassOrderController{AutowiredprivateOrderMapperorderMapper;// 直接注 MapperAutowiredprivateCommodityMappercommodityMapper;// 跨模块直接注 MapperPostMapping(/create)publicResultcreateOrder(RequestBodyOrderCreateDTOdto){// 1. 查库存直接调商品 MapperCommoditycommoditycommodityMapper.selectById(dto.getCommodityId());if(commodity.getAmount()0){returnResult.fail(库存不足);}// 2. 减库存直接写商品表commodity.setAmount(commodity.getAmount()-1);commodityMapper.updateById(commodity);// 3. 查用户直接调用户 MapperUseruseruserMapper.selectById(dto.getUserId());if(user.getCoinBalance()dto.getPrice()){returnResult.fail(余额不足);}// 4. 扣余额直接写用户表user.setCoinBalance(user.getCoinBalance()-dto.getPrice());userMapper.updateById(user);// 5. 保存订单OrderordernewOrder();order.setUserId(dto.getUserId());order.setCommodityId(dto.getCommodityId());order.setAmount(dto.getPrice());orderMapper.insert(order);returnResult.success(order);}}问题一个下单操作直接跨了 3 个数据库表没有任何边界。哪天有人改了商品表字段订单模块直接崩。改造后微服务// 订单服务 —— 只调自己的 Service跨服务走 FeignRestControllerRequestMapping(/order)publicclassOrderController{AutowiredprivateOrderServiceorderService;// 自己的 ServicePostMapping(/create)publicResultOrderVOcreate(RequestBodyOrderCreateDTOdto){returnResult.success(orderService.createOrder(dto));}}// 订单服务 —— Service 层做编排ServicepublicclassOrderService{AutowiredprivateOrderMapperorderMapper;// 自己模块的 MapperAutowiredprivateCommodityFeigncommodityFeign;// Feign 调商品服务AutowiredprivateUserFeignuserFeign;// Feign 调用户服务TransactionalpublicOrderVOcreateOrder(OrderCreateDTOdto){// 1. 远程查商品信息调用商品服务RCommodityDTOrcommodityFeign.getById(dto.getCommodityId());CommodityDTOcommodityr.getData();if(commodity.getStock()0){thrownewBusinessException(库存不足);}// 2. 远程减库存调用商品服务commodityFeign.deductStock(dto.getCommodityId(),1);// 3. 远程扣款调用用户服务userFeign.deductBalance(dto.getUserId(),dto.getPrice());// 4. 保存订单OrderordernewOrder();order.setUserId(dto.getUserId());order.setCommodityId(dto.getCommodityId());orderMapper.insert(order);returnOrderVO.from(order);}}核心变化Autowired CommodityMapper→Autowired CommodityFeign不再直接操作别人的数据库跨模块调用从本地方法调用变成远程 HTTP 调用每个服务只管自己的数据库3.2 Feign 接口设计API 模块集中管理// 放在 project-api/project-commodity-api 中不是商品服务的实现模块// 这样订单服务只依赖 api不依赖商品服务的整个实现FeignClient(nameproject-commodity,path/commodity)publicinterfaceCommodityFeign{GetMapping(/{id})RCommodityDTOgetById(PathVariable(id)Longid);PutMapping(/stock/deduct)RVoiddeductStock(RequestParam(id)Longid,RequestParam(count)Integercount);}// 商品服务实现 Feign 对应的 ControllerRestControllerRequestMapping(/commodity)publicclassCommodityFeignController{AutowiredprivateCommodityServicecommodityService;GetMapping(/{id})publicRCommodityDTOgetById(PathVariable(id)Longid){CommodityentitycommodityService.getById(id);// Entity → DTO不暴露数据库表结构CommodityDTOdtonewCommodityDTO();dto.setId(entity.getId());dto.setName(entity.getName());dto.setPrice(entity.getPrice());dto.setStock(entity.getAmount()-entity.getSoldCount());returnR.ok(dto);}PutMapping(/stock/deduct)publicRVoiddeductStock(RequestParam(id)Longid,RequestParam(count)Integercount){commodityService.deductStock(id,count);returnR.ok();}}为什么 Feign 要独立成 api 模块❌ 错误做法 订单服务的 pom.xml 里直接依赖商品服务的实现模块 → 订单服务能访问商品服务的所有类耦合失控 ✅ 正确做法 订单服务只依赖 commodity-api只有 Feign 接口 DTO 定义 → 只能通过 Feign 接口调用边界清晰3.3 公共模块拆分改造前大杂烩 common// 所有东西扔在一个 common 模块里com.xxx.common/├── result/R.java # 统一响应 ├── exception/BizException.java # 业务异常 ├── utils/│ ├──JwtUtil.java #JWT工具 │ ├──RedisUtil.java #Redis工具 │ ├──OrderUtil.java # ❌ 订单业务工具不应该在 common │ └──CommodityUtil.java # ❌ 商品业务工具不应该在 common ├── entity/│ ├──User.java # ❌ 不应该共享实体 │ └──Order.java # ❌ 不应该共享实体 └── dto/# 所有DTO混在一起改造后按职责拆project-framework/ ├── project-common-core/ # 只放真正通用的东西 │ └── com.xxx.framework.common/ │ ├── result/R.java # 统一响应 │ ├── exception/ # 基础异常 │ ├── enums/BaseEnum.java # 枚举基类 │ └── utils/IdWorker.java # 真正的基础工具 │ ├── project-common-security/ # 安全相关独立 │ └── com.xxx.framework.security/ │ ├── JwtUtil.java │ └── SecurityConfig.java │ └── project-api/ # Feign 接口独立 └── com.xxx.api.feign/ ├── CommodityFeign.java └── OrderFeign.java判断标准能不能放 common示例✅ 所有服务都用到R.java、基础异常✅ 与业务无关雪花算法 ID 生成器❌ 只有一两个服务用到OrderUtil❌ 包含业务逻辑价格计算工具❌ 数据库实体User.java、Order.java四、完整微服务内部结构每个微服务内部采用分层架构project-user/ ├── pom.xml └── src/main/java/com/xxx/user/ │ ├── controller/ # 接口层接收请求、参数校验 │ ├── UserController.java # 给前端用的接口 │ └── UserFeignController.java # 给其他服务 Feign 调用的接口 │ ├── service/ # 业务层核心逻辑、事务管理 │ ├── UserService.java │ └── impl/ │ └── UserServiceImpl.java │ ├── mapper/ # 数据访问层 │ └── UserMapper.java │ ├── domain/ # 领域模型 │ ├── User.java # 数据库实体 │ └── enums/ │ └── UserStatusEnum.java │ ├── dto/ # 数据传输对象 │ ├── request/ │ │ └── UserRegisterReq.java # 入参 │ └── response/ │ └── UserInfoResp.java # 出参 │ ├── infrastructure/ # 基础设施外部服务调用 │ └── OrderFeignClient.java # 封装对订单服务的 Feign 调用 │ └── config/ # 本服务专属配置 └── MyBatisConfig.java五、改造检查清单从单体改微服务逐个排查检查项问题表现怎么改Controller 直接注 MapperAutowired private UserMapper改注 Service跨模块注 MapperOrderService 注 CommodityMapper改注 CommodityFeign跨模块写表OrderService 直接 update commodity 表走 Feign 调商品服务共享 Entitycommon 里有 User.javaEntity 归位到各自服务DTO/VO/Entity 混用Controller 直接返回 Entity用 VO 包装Feign 返回 EntityROrder暴露表结构返回ROrderDTOcommon 大杂烩业务工具类放 common移回各自服务所有 Feign 混一起模块依赖了整个 api 包拆成独立 api 模块六、总结维度单体微服务部署改一行全量部署改一个服务只部署一个故障隔离一处崩溃全局不可用服务隔离互不影响团队协作所有人改一个项目各团队独立维护数据库所有表在一个库随意 JOIN每个服务独立数据库通过 Feign 通信扩展性整个项目一起扩缩只扩高负载的服务复杂度简单需要注册中心、配置中心、网关、链路追踪微服务不是银弹。项目初期 3-5 人团队业务简单用单体反而更高效。微服务是随着业务增长、团队扩大后的自然演进结果。