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核心优势
- 清晰的分层架构:职责分明,易于维护
- 领域驱动设计:代码即文档,业务知识沉淀
- 可扩展性强:扩展点机制支持灵活扩展
- 测试友好:领域逻辑独立,便于单元测试
- 规范统一:团队协作效率高
8.2 实施建议
实施步骤:
1. 团队培训 → 统一认识DDD和COLA
2. 试点项目 → 选择中小型模块试点
3. 总结经验 → 形成团队最佳实践
4. 全面推广 → 逐步应用到所有项目
8.3 学习资源
- 官方文档: https://github.com/alibaba/COLA
- 示例项目: https://github.com/alibaba/COLA/tree/master/cola-samples
- 社区交流: 钉钉群、GitHub Issues
8.4 架构演进路径
阶段1: 基础分层
├─ 按照COLA模块结构组织代码
└─ 明确各层职责
阶段2: 领域建模
├─ 识别聚合根和实体
├─ 提炼值对象
└─ 定义领域服务
阶段3: 高级特性
├─ 使用扩展点支持多租户
├─ 引入CQRS分离读写
└─ 应用领域事件解耦
阶段4: 持续优化
├─ 重构贫血模型为充血模型
├─ 优化聚合边界
└─ 提升代码质量