COLA架构实战

COLA架构实战指南:构建整洁的企业级应用

一、COLA架构简介

1.1 什么是COLA

COLA(Clean Object-Oriented and Layered Architecture)是阿里巴巴开源的一套应用架构规范,旨在帮助开发者构建整洁、可维护、可扩展的企业级应用系统。COLA不仅仅是一个框架,更是一套完整的架构思想和最佳实践。

1.2 COLA解决的核心问题

在传统的企业应用开发中,我们经常遇到以下问题:

  • 代码结构混乱:业务逻辑、数据访问、UI展示混杂在一起
  • 扩展性差:新增功能需要修改大量已有代码
  • 测试困难:业务逻辑与基础设施耦合,单元测试难以编写
  • 领域知识流失:代码无法反映业务领域模型

COLA通过分层架构和DDD(领域驱动设计)思想,为这些问题提供了系统化的解决方案。

1.3 COLA架构分层

复制代码
┌─────────────────────────────────────────────────────┐
│                   Adapter Layer                      │
│  ┌──────────────┐  ┌──────────────┐  ┌───────────┐ │
│  │ Web/API      │  │ Message      │  │ Schedule  │ │
│  │ Controller   │  │ Listener     │  │ Task      │ │
│  └──────────────┘  └──────────────┘  └───────────┘ │
└─────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────┐
│                    App Layer                         │
│  ┌──────────────────────────────────────────────┐  │
│  │  Application Service (Command/Query)         │  │
│  │  - Orchestration Logic                       │  │
│  │  - Transaction Management                    │  │
│  └──────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────┐
│                   Domain Layer                       │
│  ┌──────────────┐  ┌──────────────┐  ┌───────────┐ │
│  │ Entity       │  │ Value Object │  │ Domain    │ │
│  │              │  │              │  │ Service   │ │
│  └──────────────┘  └──────────────┘  └───────────┘ │
└─────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────┐
│              Infrastructure Layer                    │
│  ┌──────────────┐  ┌──────────────┐  ┌───────────┐ │
│  │ Repository   │  │ Gateway      │  │ Config    │ │
│  │ Impl         │  │              │  │           │ │
│  └──────────────┘  └──────────────┘  └───────────┘ │
└─────────────────────────────────────────────────────┘

二、快速开始:使用COLA脚手架

2.1 环境准备

确保你的开发环境已安装:

  • JDK 8+
  • Maven 3.5+
  • IDE(推荐IDEA)

2.2 创建COLA项目

使用Maven Archetype创建COLA项目:

bash 复制代码
mvn archetype:generate \
    -DgroupId=com.example \
    -DartifactId=order-system \
    -Dversion=1.0.0-SNAPSHOT \
    -Dpackage=com.example.order \
    -DarchetypeArtifactId=cola-framework-archetype-service \
    -DarchetypeGroupId=com.alibaba.cola \
    -DarchetypeVersion=4.3.1

2.3 项目模块结构

生成的项目包含以下模块:

复制代码
order-system
├── order-adapter           # 适配层
│   ├── api                 # API适配器
│   └── web                 # Web适配器
├── order-app               # 应用层
├── order-domain            # 领域层
├── order-infrastructure    # 基础设施层
└── start                   # 启动模块

三、实战案例:构建订单系统

我们以一个电商订单系统为例,展示如何使用COLA架构进行开发。

3.1 定义领域模型(Domain Layer)

3.1.1 订单实体
java 复制代码
package com.example.order.domain.order;

import com.alibaba.cola.domain.Entity;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 订单聚合根
 */
@Data
@Entity
public class Order {

    private OrderId orderId;
    private UserId userId;
    private OrderStatus status;
    private List<OrderItem> items;
    private Money totalAmount;
    private Address shippingAddress;
    private LocalDateTime createdTime;

    /**
     * 创建订单 - 领域行为
     */
    public static Order create(UserId userId, List<OrderItem> items, Address address) {
        Order order = new Order();
        order.orderId = OrderId.generate();
        order.userId = userId;
        order.items = items;
        order.shippingAddress = address;
        order.status = OrderStatus.PENDING;
        order.totalAmount = calculateTotal(items);
        order.createdTime = LocalDateTime.now();

        // 领域规则验证
        order.validate();

        return order;
    }

    /**
     * 支付订单
     */
    public void pay() {
        if (this.status != OrderStatus.PENDING) {
            throw new OrderException("订单状态不允许支付");
        }
        this.status = OrderStatus.PAID;
    }

    /**
     * 发货
     */
    public void ship() {
        if (this.status != OrderStatus.PAID) {
            throw new OrderException("订单未支付,不能发货");
        }
        this.status = OrderStatus.SHIPPED;
    }

    /**
     * 完成订单
     */
    public void complete() {
        if (this.status != OrderStatus.SHIPPED) {
            throw new OrderException("订单未发货,不能完成");
        }
        this.status = OrderStatus.COMPLETED;
    }

    /**
     * 取消订单
     */
    public void cancel() {
        if (this.status == OrderStatus.SHIPPED || this.status == OrderStatus.COMPLETED) {
            throw new OrderException("订单已发货或已完成,不能取消");
        }
        this.status = OrderStatus.CANCELLED;
    }

    private static Money calculateTotal(List<OrderItem> items) {
        BigDecimal total = items.stream()
            .map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        return new Money(total);
    }

    private void validate() {
        if (items == null || items.isEmpty()) {
            throw new OrderException("订单明细不能为空");
        }
        if (totalAmount.isLessThanOrEqualTo(Money.ZERO)) {
            throw new OrderException("订单金额必须大于0");
        }
        if (shippingAddress == null) {
            throw new OrderException("收货地址不能为空");
        }
    }
}
3.1.2 值对象
java 复制代码
package com.example.order.domain.order;

import com.alibaba.cola.domain.ValueObject;
import lombok.Value;
import java.math.BigDecimal;

/**
 * 金额值对象
 */
@Value
public class Money implements ValueObject {

    public static final Money ZERO = new Money(BigDecimal.ZERO);

    BigDecimal amount;

    public Money(BigDecimal amount) {
        if (amount == null) {
            throw new IllegalArgumentException("金额不能为null");
        }
        this.amount = amount.setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    public Money add(Money other) {
        return new Money(this.amount.add(other.amount));
    }

    public Money subtract(Money other) {
        return new Money(this.amount.subtract(other.amount));
    }

    public Money multiply(int multiplier) {
        return new Money(this.amount.multiply(new BigDecimal(multiplier)));
    }

    public boolean isGreaterThan(Money other) {
        return this.amount.compareTo(other.amount) > 0;
    }

    public boolean isLessThanOrEqualTo(Money other) {
        return this.amount.compareTo(other.amount) <= 0;
    }
}
java 复制代码
package com.example.order.domain.order;

import com.alibaba.cola.domain.ValueObject;
import lombok.Value;

/**
 * 收货地址值对象
 */
@Value
public class Address implements ValueObject {

    String province;
    String city;
    String district;
    String street;
    String detail;
    String zipCode;
    String receiverName;
    String receiverPhone;

    public String getFullAddress() {
        return province + city + district + street + detail;
    }

    public void validate() {
        if (province == null || city == null || detail == null) {
            throw new IllegalArgumentException("地址信息不完整");
        }
        if (receiverName == null || receiverPhone == null) {
            throw new IllegalArgumentException("收货人信息不完整");
        }
    }
}
3.1.3 领域服务
java 复制代码
package com.example.order.domain.order;

import com.alibaba.cola.domain.DomainService;
import org.springframework.stereotype.Service;

/**
 * 订单定价领域服务
 */
@Service
@DomainService
public class OrderPricingService {

    /**
     * 计算订单优惠后价格
     */
    public Money calculateDiscountedPrice(Order order, Coupon coupon) {
        Money originalPrice = order.getTotalAmount();

        if (coupon == null) {
            return originalPrice;
        }

        // 应用优惠券
        switch (coupon.getType()) {
            case PERCENTAGE:
                BigDecimal discountRate = coupon.getDiscountValue().divide(new BigDecimal(100));
                BigDecimal discountAmount = originalPrice.getAmount().multiply(discountRate);
                return new Money(originalPrice.getAmount().subtract(discountAmount));

            case FIXED_AMOUNT:
                Money discount = new Money(coupon.getDiscountValue());
                if (discount.isGreaterThan(originalPrice)) {
                    return Money.ZERO;
                }
                return originalPrice.subtract(discount);

            default:
                return originalPrice;
        }
    }

    /**
     * 计算运费
     */
    public Money calculateShippingFee(Order order) {
        Money totalAmount = order.getTotalAmount();

        // 满99免运费
        if (totalAmount.isGreaterThan(new Money(new BigDecimal("99.00")))) {
            return Money.ZERO;
        }

        // 基础运费
        return new Money(new BigDecimal("10.00"));
    }
}

3.2 应用层(App Layer)

3.2.1 Command对象(命令)
java 复制代码
package com.example.order.app.order.command;

import com.alibaba.cola.dto.Command;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

/**
 * 创建订单命令
 */
@Data
public class CreateOrderCmd extends Command {

    @NotNull(message = "用户ID不能为空")
    private Long userId;

    @NotEmpty(message = "订单商品不能为空")
    private List<OrderItemDto> items;

    @NotNull(message = "收货地址不能为空")
    private AddressDto shippingAddress;

    private String couponCode;

    @Data
    public static class OrderItemDto {
        @NotNull
        private Long productId;
        @NotNull
        private String productName;
        @NotNull
        private BigDecimal price;
        @NotNull
        private Integer quantity;
    }

    @Data
    public static class AddressDto {
        private String province;
        private String city;
        private String district;
        private String street;
        private String detail;
        private String zipCode;
        private String receiverName;
        private String receiverPhone;
    }
}
3.2.2 应用服务
java 复制代码
package com.example.order.app.order;

import com.alibaba.cola.catchlog.CatchAndLog;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import com.example.order.app.order.command.CreateOrderCmd;
import com.example.order.domain.order.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 订单应用服务
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderRepository orderRepository;

    @Resource
    private OrderPricingService pricingService;

    @Resource
    private CouponGateway couponGateway;

    @Resource
    private InventoryGateway inventoryGateway;

    @Resource
    private OrderEventPublisher eventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CatchAndLog
    public SingleResponse<String> createOrder(CreateOrderCmd cmd) {

        // 1. 组装领域对象
        UserId userId = new UserId(cmd.getUserId());
        List<OrderItem> items = convertToOrderItems(cmd.getItems());
        Address address = convertToAddress(cmd.getShippingAddress());

        // 2. 检查库存
        boolean stockAvailable = inventoryGateway.checkStock(items);
        if (!stockAvailable) {
            return SingleResponse.buildFailure("STOCK_NOT_ENOUGH", "库存不足");
        }

        // 3. 创建订单(领域逻辑)
        Order order = Order.create(userId, items, address);

        // 4. 应用优惠券
        if (cmd.getCouponCode() != null) {
            Coupon coupon = couponGateway.getCoupon(cmd.getCouponCode());
            if (coupon != null && coupon.isValid()) {
                Money discountedPrice = pricingService.calculateDiscountedPrice(order, coupon);
                order.applyDiscount(discountedPrice);
            }
        }

        // 5. 计算运费
        Money shippingFee = pricingService.calculateShippingFee(order);
        order.addShippingFee(shippingFee);

        // 6. 扣减库存
        inventoryGateway.deductStock(items);

        // 7. 持久化订单
        orderRepository.save(order);

        // 8. 发布领域事件
        eventPublisher.publish(new OrderCreatedEvent(order.getOrderId()));

        return SingleResponse.of(order.getOrderId().getValue());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CatchAndLog
    public Response payOrder(String orderId) {
        // 1. 加载订单
        Order order = orderRepository.getById(new OrderId(orderId));
        if (order == null) {
            return Response.buildFailure("ORDER_NOT_FOUND", "订单不存在");
        }

        // 2. 执行支付(领域行为)
        order.pay();

        // 3. 保存订单
        orderRepository.save(order);

        // 4. 发布领域事件
        eventPublisher.publish(new OrderPaidEvent(order.getOrderId()));

        return Response.buildSuccess();
    }

    private List<OrderItem> convertToOrderItems(List<CreateOrderCmd.OrderItemDto> dtos) {
        return dtos.stream()
            .map(dto -> new OrderItem(
                new ProductId(dto.getProductId()),
                dto.getProductName(),
                new Money(dto.getPrice()),
                dto.getQuantity()
            ))
            .collect(Collectors.toList());
    }

    private Address convertToAddress(CreateOrderCmd.AddressDto dto) {
        return new Address(
            dto.getProvince(),
            dto.getCity(),
            dto.getDistrict(),
            dto.getStreet(),
            dto.getDetail(),
            dto.getZipCode(),
            dto.getReceiverName(),
            dto.getReceiverPhone()
        );
    }
}

3.3 基础设施层(Infrastructure Layer)

3.3.1 Repository实现
java 复制代码
package com.example.order.infrastructure.order;

import com.example.order.domain.order.Order;
import com.example.order.domain.order.OrderId;
import com.example.order.domain.order.OrderRepository;
import com.example.order.infrastructure.order.mapper.OrderMapper;
import com.example.order.infrastructure.order.dataobject.OrderDO;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;

/**
 * 订单仓储实现
 */
@Repository
public class OrderRepositoryImpl implements OrderRepository {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderConverter orderConverter;

    @Override
    public void save(Order order) {
        OrderDO orderDO = orderConverter.toDataObject(order);

        if (orderMapper.selectById(orderDO.getId()) == null) {
            orderMapper.insert(orderDO);
        } else {
            orderMapper.updateById(orderDO);
        }
    }

    @Override
    public Order getById(OrderId orderId) {
        OrderDO orderDO = orderMapper.selectById(orderId.getValue());
        if (orderDO == null) {
            return null;
        }
        return orderConverter.toEntity(orderDO);
    }

    @Override
    public List<Order> findByUserId(UserId userId) {
        List<OrderDO> orderDOs = orderMapper.selectByUserId(userId.getValue());
        return orderDOs.stream()
            .map(orderConverter::toEntity)
            .collect(Collectors.toList());
    }
}
3.3.2 Gateway实现(外部服务调用)
java 复制代码
package com.example.order.infrastructure.gateway;

import com.example.order.domain.order.InventoryGateway;
import com.example.order.domain.order.OrderItem;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;

/**
 * 库存服务网关实现
 */
@Component
public class InventoryGatewayImpl implements InventoryGateway {

    @Resource
    private RestTemplate restTemplate;

    private static final String INVENTORY_SERVICE_URL = "http://inventory-service";

    @Override
    public boolean checkStock(List<OrderItem> items) {
        // 调用库存服务检查库存
        CheckStockRequest request = new CheckStockRequest();
        request.setItems(items.stream()
            .map(item -> new StockItem(
                item.getProductId().getValue(),
                item.getQuantity()
            ))
            .collect(Collectors.toList()));

        CheckStockResponse response = restTemplate.postForObject(
            INVENTORY_SERVICE_URL + "/api/stock/check",
            request,
            CheckStockResponse.class
        );

        return response != null && response.isAvailable();
    }

    @Override
    public void deductStock(List<OrderItem> items) {
        DeductStockRequest request = new DeductStockRequest();
        request.setItems(items.stream()
            .map(item -> new StockItem(
                item.getProductId().getValue(),
                item.getQuantity()
            ))
            .collect(Collectors.toList()));

        restTemplate.postForObject(
            INVENTORY_SERVICE_URL + "/api/stock/deduct",
            request,
            Void.class
        );
    }
}

3.4 适配器层(Adapter Layer)

3.4.1 Web Controller
java 复制代码
package com.example.order.adapter.web;

import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import com.example.order.app.order.OrderService;
import com.example.order.app.order.command.CreateOrderCmd;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;

/**
 * 订单控制器
 */
@RestController
@RequestMapping("/api/orders")
@Api(tags = "订单管理")
public class OrderController {

    @Resource
    private OrderService orderService;

    @PostMapping
    @ApiOperation("创建订单")
    public SingleResponse<String> createOrder(@Valid @RequestBody CreateOrderCmd cmd) {
        return orderService.createOrder(cmd);
    }

    @PostMapping("/{orderId}/pay")
    @ApiOperation("支付订单")
    public Response payOrder(@PathVariable String orderId) {
        return orderService.payOrder(orderId);
    }

    @PostMapping("/{orderId}/ship")
    @ApiOperation("订单发货")
    public Response shipOrder(@PathVariable String orderId) {
        return orderService.shipOrder(orderId);
    }

    @PostMapping("/{orderId}/cancel")
    @ApiOperation("取消订单")
    public Response cancelOrder(@PathVariable String orderId) {
        return orderService.cancelOrder(orderId);
    }

    @GetMapping("/{orderId}")
    @ApiOperation("查询订单详情")
    public SingleResponse<OrderDetailDto> getOrderDetail(@PathVariable String orderId) {
        return orderService.getOrderDetail(orderId);
    }
}

四、COLA核心特性详解

4.1 CQRS(命令查询职责分离)

COLA推荐使用CQRS模式,将命令(修改操作)和查询(读取操作)分离。

java 复制代码
// 命令侧 - 用于修改状态
public interface OrderCommandService {
    Response createOrder(CreateOrderCmd cmd);
    Response updateOrder(UpdateOrderCmd cmd);
}

// 查询侧 - 用于读取数据
public interface OrderQueryService {
    SingleResponse<OrderDto> getOrderById(String orderId);
    MultiResponse<OrderDto> listOrders(OrderQuery query);
}

查询服务实现示例:

java 复制代码
package com.example.order.app.order.query;

import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.dto.MultiResponse;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class OrderQueryServiceImpl implements OrderQueryService {

    @Resource
    private OrderMapper orderMapper;

    @Override
    public SingleResponse<OrderDto> getOrderById(String orderId) {
        OrderDO orderDO = orderMapper.selectById(orderId);
        if (orderDO == null) {
            return SingleResponse.buildFailure("ORDER_NOT_FOUND", "订单不存在");
        }

        OrderDto dto = convertToDto(orderDO);
        return SingleResponse.of(dto);
    }

    @Override
    public MultiResponse<OrderDto> listOrders(OrderQuery query) {
        // 直接查询数据库,不经过领域层
        List<OrderDO> orderDOs = orderMapper.selectByCondition(query);
        List<OrderDto> dtos = orderDOs.stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());

        return MultiResponse.of(dtos);
    }
}

4.2 扩展点机制(Extension Point)

COLA提供了强大的扩展点机制,支持业务的动态扩展。

java 复制代码
package com.example.order.domain.order.extension;

import com.alibaba.cola.extension.ExtensionPointI;

/**
 * 订单创建扩展点
 */
public interface OrderCreationExtPt extends ExtensionPointI {

    /**
     * 订单创建前置处理
     */
    void beforeCreate(Order order);

    /**
     * 订单创建后置处理
     */
    void afterCreate(Order order);
}

不同业务场景的实现:

java 复制代码
package com.example.order.domain.order.extension;

import com.alibaba.cola.extension.Extension;
import org.springframework.stereotype.Component;

/**
 * 普通订单扩展实现
 */
@Extension(bizId = "normal")
@Component
public class NormalOrderCreationExt implements OrderCreationExtPt {

    @Override
    public void beforeCreate(Order order) {
        // 普通订单的前置处理
        System.out.println("普通订单创建前检查");
    }

    @Override
    public void afterCreate(Order order) {
        // 发送普通订单创建通知
        System.out.println("发送普通订单创建通知");
    }
}

/**
 * VIP订单扩展实现
 */
@Extension(bizId = "vip")
@Component
public class VipOrderCreationExt implements OrderCreationExtPt {

    @Override
    public void beforeCreate(Order order) {
        // VIP订单的特殊处理
        System.out.println("VIP订单创建前检查,应用VIP优惠");
    }

    @Override
    public void afterCreate(Order order) {
        // 发送VIP专属通知
        System.out.println("发送VIP订单创建通知,赠送积分");
    }
}

使用扩展点:

java 复制代码
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderCreationExtPt orderCreationExtPt;

    @Override
    public SingleResponse<String> createOrder(CreateOrderCmd cmd) {
        // 创建订单
        Order order = Order.create(...);

        // 根据业务类型执行不同的扩展逻辑
        String bizId = determineBizId(cmd.getUserId());
        orderCreationExtPt.beforeCreate(order);

        // 保存订单
        orderRepository.save(order);

        orderCreationExtPt.afterCreate(order);

        return SingleResponse.of(order.getOrderId().getValue());
    }
}

4.3 领域事件

java 复制代码
package com.example.order.domain.order.event;

import com.alibaba.cola.event.DomainEventI;
import lombok.Value;

/**
 * 订单已创建事件
 */
@Value
public class OrderCreatedEvent implements DomainEventI {
    OrderId orderId;
    UserId userId;
    Money totalAmount;
    LocalDateTime occurredOn;
}

/**
 * 订单已支付事件
 */
@Value
public class OrderPaidEvent implements DomainEventI {
    OrderId orderId;
    Money paidAmount;
    LocalDateTime occurredOn;
}

事件发布和订阅:

java 复制代码
package com.example.order.infrastructure.event;

import com.example.order.domain.order.event.OrderCreatedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

/**
 * 订单事件监听器
 */
@Component
public class OrderEventListener {

    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        // 发送创建订单通知
        System.out.println("订单创建通知: " + event.getOrderId());

        // 其他业务逻辑:积分、优惠券等
    }

    @EventListener
    public void handleOrderPaid(OrderPaidEvent event) {
        // 触发发货流程
        System.out.println("订单已支付,准备发货: " + event.getOrderId());
    }
}

五、与Spring Boot集成

5.1 Maven依赖配置

xml 复制代码
<dependencies>
    <!-- COLA Framework -->
    <dependency>
        <groupId>com.alibaba.cola</groupId>
        <artifactId>cola-component-dto</artifactId>
        <version>4.3.1</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cola</groupId>
        <artifactId>cola-component-extension-starter</artifactId>
        <version>4.3.1</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cola</groupId>
        <artifactId>cola-component-catchlog-starter</artifactId>
        <version>4.3.1</version>
    </dependency>

    <!-- Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- MyBatis Plus -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.2</version>
    </dependency>
</dependencies>

5.2 应用启动类

java 复制代码
package com.example.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.alibaba.cola.boot.ColaBoot;

@SpringBootApplication
@ColaBoot
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

六、最佳实践与注意事项

6.1 分层职责清晰

复制代码
层次          职责                      禁止事项
────────────────────────────────────────────────────
Adapter      适配外部请求              不能包含业务逻辑
             参数校验                  不能直接访问DB
             协议转换
────────────────────────────────────────────────────
App          业务流程编排              不能包含领域逻辑
             事务控制                  不能直接操作DO
             权限控制
────────────────────────────────────────────────────
Domain       核心业务逻辑              不依赖外部框架
             领域模型                  不包含技术细节
             业务规则
────────────────────────────────────────────────────
Infrastructure 数据持久化              只负责技术实现
               外部服务调用            不包含业务逻辑
               技术组件

6.2 依赖方向原则

复制代码
┌─────────────┐
│   Adapter   │ ──┐
└─────────────┘   │
                  ↓
┌─────────────┐   │
│     App     │ ──┤  所有层都依赖Domain
└─────────────┘   │
                  ↓
┌─────────────┐   │
│Infrastructure│──┘
└─────────────┘
       ↑
       │
┌─────────────┐
│   Domain    │ ← 核心层,不依赖任何其他层
└─────────────┘

6.3 实体与DTO转换

错误做法:

java 复制代码
// ❌ 在Controller直接返回Entity
@GetMapping("/{id}")
public Order getOrder(@PathVariable Long id) {
    return orderRepository.findById(id);
}

正确做法:

java 复制代码
// ✅ 使用DTO进行数据传输
@GetMapping("/{id}")
public SingleResponse<OrderDto> getOrder(@PathVariable Long id) {
    Order order = orderRepository.findById(id);
    OrderDto dto = OrderAssembler.toDto(order);
    return SingleResponse.of(dto);
}

6.4 贫血模型 vs 充血模型

COLA推荐使用充血模型,将业务逻辑放在领域对象中。

贫血模型(不推荐):

java 复制代码
// 实体只有getter/setter
public class Order {
    private String status;
    // getters and setters
}

// 业务逻辑在Service中
public class OrderService {
    public void payOrder(Order order) {
        if (!"PENDING".equals(order.getStatus())) {
            throw new Exception("状态错误");
        }
        order.setStatus("PAID");
    }
}

充血模型(推荐):

java 复制代码
// 业务逻辑在实体中
public class Order {
    private OrderStatus status;

    public void pay() {
        if (this.status != OrderStatus.PENDING) {
            throw new OrderException("订单状态不允许支付");
        }
        this.status = OrderStatus.PAID;
    }
}

// Service只负责编排
public class OrderService {
    public void payOrder(String orderId) {
        Order order = orderRepository.findById(orderId);
        order.pay();  // 调用领域行为
        orderRepository.save(order);
    }
}

七、与其他框架对比

7.1 COLA vs 传统三层架构

复制代码
传统三层架构              COLA架构
───────────────────     ───────────────────
Controller              Adapter
  ↓                       ↓
Service (所有逻辑)      App (流程编排)
  ↓                       ↓
DAO                     Domain (核心逻辑)
                          ↓
                        Infrastructure

主要区别:

  • 传统架构业务逻辑分散在Service,COLA集中在Domain
  • 传统架构面向数据建模,COLA面向领域建模
  • COLA有明确的扩展点机制,支持多租户场景

7.2 COLA在实际项目中的应用场景

适用场景:

  • 复杂业务系统(电商、金融、物流等)
  • 多租户SaaS平台
  • 需要长期维护的企业级应用
  • 业务规则频繁变化的系统

不适用场景:

  • 简单的CRUD应用
  • 快速原型开发
  • 小型工具类项目

八、总结

8.1 COLA核心优势

  1. 清晰的分层架构:职责分明,易于维护
  2. 领域驱动设计:代码即文档,业务知识沉淀
  3. 可扩展性强:扩展点机制支持灵活扩展
  4. 测试友好:领域逻辑独立,便于单元测试
  5. 规范统一:团队协作效率高

8.2 实施建议

复制代码
实施步骤:
1. 团队培训 → 统一认识DDD和COLA
2. 试点项目 → 选择中小型模块试点
3. 总结经验 → 形成团队最佳实践
4. 全面推广 → 逐步应用到所有项目

8.3 学习资源

8.4 架构演进路径

复制代码
阶段1: 基础分层
  ├─ 按照COLA模块结构组织代码
  └─ 明确各层职责

阶段2: 领域建模
  ├─ 识别聚合根和实体
  ├─ 提炼值对象
  └─ 定义领域服务

阶段3: 高级特性
  ├─ 使用扩展点支持多租户
  ├─ 引入CQRS分离读写
  └─ 应用领域事件解耦

阶段4: 持续优化
  ├─ 重构贫血模型为充血模型
  ├─ 优化聚合边界
  └─ 提升代码质量
相关推荐
断剑zou天涯8 小时前
【算法笔记】Manacher算法
java·笔记·算法
梦未8 小时前
Spring控制反转与依赖注入
java·后端·spring
喜欢流萤吖~8 小时前
Lambda 表达式
java
ZouZou老师8 小时前
C++设计模式之适配器模式:以家具生产为例
java·设计模式·适配器模式
曼巴UE59 小时前
UE5 C++ 动态多播
java·开发语言
VX:Fegn08959 小时前
计算机毕业设计|基于springboot + vue音乐管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
程序员鱼皮9 小时前
刚刚,IDEA 免费版发布!终于不用破解了
java·程序员·jetbrains
腾讯云中间件9 小时前
腾讯云 RocketMQ 5.x:如何兼容 Remoting 全系列客户端
架构·消息队列·rocketmq
Hui Baby9 小时前
Nacos容灾俩种方案对比
java