首页
Preview

Spring Cloud微服务框架,实战企业级优惠券系统(14章完结)

t04d37b5ecd00109676.jpg

在微服务架构的演进过程中,将单体应用拆分为高内聚、低耦合的微服务是架构师面临的首要挑战。优惠券系统作为电商平台中流量高频、逻辑复杂的典型业务,是演练 Spring Cloud 企业级实战的最佳场景。它不仅涉及商品的精准营销,还直接关联订单金额和资金流转,对系统的可用性和一致性要求极高。

在设计优惠券系统的微服务架构时,我们不能简单地按照 DAO 层或 Controller 层拆分,而应该依据业务领域(DDD)进行划分。基于此,我们可以将系统核心拆分为三个关键服务:

优惠券服务:负责优惠券模板的创建、发放、核销规则的配置以及优惠券的生命周期管理。 用户服务:专注于用户账户信息、等级以及用户持有的优惠券资产(库存管理)。 营销活动服务:负责大促活动的规则配置(如满减、折扣)与活动范围控制。 这种拆分方式使得优惠券服务可以专注于规则引擎的计算,而用户服务则专注于资产的扣减,职责清晰。在实际落地中,服务拆分后紧接着要解决的就是分布式调用和网关路由问题。

为了演示这一架构设计,我们将使用 Spring Cloud 的核心组件构建一个简化的实战案例。假设用户需要通过网关查询可用的优惠券列表,并使用一张优惠券。

首先,我们需要一个API 网关作为系统的统一入口,负责路由转发和鉴权。这里使用 Spring Cloud Gateway:

application.yml (Gateway 服务配置)

server: port: 9000 spring: application: name: coupon-gateway cloud: gateway: routes: # 将请求 /coupon/** 转发到 coupon-service - id: coupon-service uri: lb://coupon-service predicates: - Path=/coupon/** # 将请求 /user/** 转发到 user-service - id: user-service uri: lb://user-service predicates: - Path=/user/** eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ 接下来是优惠券服务的核心逻辑。在 Spring Cloud 环境中,服务间调用通常使用 OpenFeign。优惠券服务需要验证优惠券是否存在,但这通常由优惠券自身逻辑处理。这里我们模拟一个更复杂的场景:用户服务调用优惠券服务来“校验并锁定”一张优惠券。

优惠券服务暴露接口:

// 优惠券服务 Controller @RestController @RequestMapping("/coupon") public class CouponController {

@Autowired
private CouponService couponService;

// 模拟的优惠券数据存储
private static final Map<Long, Coupon> COUPON_DB = new HashMap<>();

static {
    // 初始化一张测试优惠券
    COUPON_DB.put(1L, new Coupon(1L, "100减10", 1000, 10));
}

/**
 * 校验优惠券并尝试锁定(预扣除)
 * 使用 Feign 暴露给其他服务调用
 */
@PostMapping("/lock")
public Boolean lockCoupon(@RequestParam Long userId, @RequestParam Long couponId) {
    Coupon coupon = COUPON_DB.get(couponId);
    if (coupon != null && coupon.getStock() > 0) {
        coupon.setStock(coupon.getStock() - 1);
        System.out.printf("优惠券 %s 库存锁定成功,剩余库存: %d%n", coupon.getName(), coupon.getStock());
        return true;
    }
    System.out.println("优惠券库存不足或不存在");
    return false;
}

}

// 简单的实体类 @Data @AllArgsConstructor @NoArgsConstructor class Coupon { private Long id; private String name; private Integer stock; private Integer discountAmount; } 然后是用户服务通过 Feign 调用优惠券服务:

// 用户服务中的 Feign 客户端接口 @FeignClient(name = "coupon-service") public interface CouponClient { @PostMapping("/coupon/lock") Boolean lockCoupon(@RequestParam("userId") Long userId, @RequestParam("couponId") Long couponId); }

// 用户服务 Controller,模拟业务编排 @RestController @RequestMapping("/user") public class UserController {

@Autowired
private CouponClient couponClient;

@PostMapping("/order/use-coupon")
public String createOrderWithCoupon(@RequestParam Long userId, @RequestParam Long couponId) {
    // 1. 调用优惠券服务锁定库存
    boolean lockResult = couponClient.lockCoupon(userId, couponId);

    if (!lockResult) {
        return "下单失败:优惠券不可用";
    }

    // 2. 创建订单逻辑(省略)...
    System.out.println("订单创建成功,扣减优惠券库存");

    return "下单成功";
}

} 在这个实战模型中,我们通过 Spring Cloud Gateway 实现了流量的统一分发,通过 Spring Cloud Eureka(假设已启动)实现了服务注册与发现,通过 OpenFeign 实现了服务间的声明式调用。这正是 Spring Cloud 企业级开发的标准化流程。

此外,真实的优惠券系统还需要考虑分布式事务的问题。例如,如果订单创建成功但优惠券库存回滚失败,将导致资损。因此,在生产级代码中,我们需要引入 Seata 或 RocketMQ 事务消息来保证 UserController 中的远程调用与本地操作的一致性。

通过这套拆分方案,我们将复杂的业务逻辑下沉到了不同的微服务中,不仅让代码结构更清晰,也使得各服务可以独立扩展(如优惠券服务在大促期间单独增加节点),从而真正发挥了微服务架构的优势。

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
mWQDtL9yS0
暂无描述

评论(0)

添加评论