架构设计之COLA架构实战

理论必须结合实践才能发挥价值。本章将以一个经典的**"用户注册"**场景为例,演示如何使用 COLA 架构从零开始构建并开发一个功能。我们将遵循由外向内定义接口、由内向外实现核心的开发路径。

5.1 第一步:脚手架生成(初始化)

COLA 最大的便利之一是提供了标准的 Maven Archetype。你不需要手动创建那四个模块,直接运行一条命令即可生成标准工程。

Maven命令(基于COLA 4.0):

codeBash

复制代码
mvn archetype:generate  \
    -DgroupId=com.alibaba.cola.demo \
    -DartifactId=demo-web \
    -Dversion=1.0.0-SNAPSHOT \
    -Dpackage=com.alibaba.demo \
    -DarchetypeArtifactId=cola-framework-archetype-service \
    -DarchetypeGroupId=com.alibaba.cola \
    -DarchetypeVersion=4.0.1

执行完毕后,你将得到一个标准的父子工程结构:

  • demo-web-adapter

  • demo-web-app

  • demo-web-client

  • demo-web-domain

  • demo-web-infrastructure

5.2 第二步:定义业务契约(Client层)

在 COLA 中,开发通常从"定义外部如何与我们交互"开始。

在 client 模块中,我们需要定义 DTO 和 API。

codeJava

复制代码
// 1. 定义命令请求 (UserRegisterCmd.java)
public class UserRegisterCmd extends Command {
    @NotNull
    private String userName;
    @NotNull
    private String password;
    // ... getters/setters
}

// 2. 定义服务接口 (UserServiceI.java)
public interface UserServiceI {
    Response register(UserRegisterCmd cmd);
}

5.3 第三步:构建领域模型(Domain层)

这是最关键的一步。忘掉数据库表结构,专注于业务实体。

在 domain 模块中:

codeJava

复制代码
// 1. 定义领域实体 (User.java)
// 这是一个充血模型,包含业务行为
public class User extends Entity {
    private String userName;
    private String password; // 可能是加密后的

    // 业务行为:加密密码
    public void encryptPassword() {
        this.password = DigestUtils.md5Hex(this.password);
    }
}

// 2. 定义网关接口 (UserGateway.java)
// Domain层只定义接口,不关心数据存在MySQL还是Redis
public interface UserGateway {
    void save(User user);
}

5.4 第四步:实现基础设施(Infrastructure层)

在 infrastructure 模块中,我们需要落地数据的持久化。这里会涉及 COLA 开发中常见的一个痛点:对象转换

  1. 定义 DO (Data Object): 对应数据库表结构(MyBatis-Plus/JPA实体)。

  2. 实现 Mapper: 数据库访问接口。

  3. 实现 Gateway:

codeJava

复制代码
@Component
public class UserGatewayImpl implements UserGateway {
    @Autowired
    private UserMapper userMapper;

    @Override
    public void save(User user) {
        // 核心步骤:将 Domain Entity 转换为 Infra DO
        UserDO userDO = UserConvertor.toDO(user);
        userMapper.insert(userDO);
    }
}

注:你需要编写一个 Convertor/Assembler 类来处理 User <-> UserDO 的互相转换,这是解耦的必要成本。

5.5 第五步:编排业务逻辑(App层)

在 app 模块中,通过 Executor 来串联业务流程。

codeJava

复制代码
@Component
@CommandHandler
public class UserRegisterCmdExe implements CommandExecutorI<Response, UserRegisterCmd> {

    @Autowired
    private UserGateway userGateway;

    @Override
    public Response execute(UserRegisterCmd cmd) {
        // 1. 转换 DTO -> Entity
        User user = new User();
        user.setUserName(cmd.getUserName());
        user.setPassword(cmd.getPassword());

        // 2. 执行领域业务逻辑
        user.encryptPassword(); // 调用领域能力

        // 3. 调用基础设施持久化
        userGateway.save(user);

        // 4. 返回结果
        return Response.buildSuccess();
    }
}

5.6 第六步:暴露接口(Adapter层)

最后,在 adapter 模块的 Controller 中暴露 HTTP 接口。

codeJava

复制代码
@RestController
public class UserController {

    @Autowired
    private UserServiceI userService; // 注入 Client 层的接口

    @PostMapping("/user/register")
    public Response register(@RequestBody UserRegisterCmd cmd) {
        return userService.register(cmd);
    }
}

5.7 开发心得与注意事项

  1. 关于对象转换: 你会发现 COLA 架构中存在大量的对象转换(DTO <-> Entity <-> DO)。很多初学者觉得繁琐,但切记:DTO 是为了契约的稳定性,DO 是为了数据库的映射,Entity 才是业务的核心。不混用这些对象,是防止"大泥球"腐烂的第一道防线。可以使用 MapStruct 等工具简化这一过程。

  2. 依赖原则: 永远检查你的 pom.xml。如果 domain 模块引用了 mybatis 或 spring-web,说明你的架构已经"漏气"了,请立即修正。

  3. 扩展点使用: 如果后续涉及"VIP用户注册"和"普通用户注册"逻辑不同,可以引入 COLA 的 Extension 机制,在 App 层通过 BizCode 动态路由到不同的 Executor 实现,这也是 COLA 应对复杂业务的杀手锏。

传统做法是在 Service 层写大量的 if (userType == "VIP") else if ...,导致核心代码臃肿不堪。COLA 通过 Extension(扩展点) 机制,利用多态思想完美解决了这个问题。

第一步:定义扩展点接口(Domain层)

首先,我们在 Domain 层定义一个扩展点接口,继承 ExtensionPointI。这个接口定义了那些"因人而异"的逻辑钩子。

codeJava

复制代码
package com.alibaba.demo.domain.user.gateway;

import com.alibaba.cola.extension.ExtensionPointI;

// 定义注册流程中的差异化钩子
public interface UserRegisterExtPt extends ExtensionPointI {
    // 譬如:不同用户有不同的校验逻辑
    void validate(String userName);
    
    // 譬如:注册成功后的后置处理(VIP送积分,普通用户发邮件)
    void afterRegister(String userName);
}
第二步:实现不同身份的逻辑(App层)

在 App 层(或者专门的 extension 包),我们为不同的身份编写具体的实现类,并使用 @Extension 注解进行标记。

场景 A:普通用户实现

codeJava

复制代码
@Extension(bizId = "COMMON_USER") // 标记业务身份 ID
public class CommonUserRegisterExt implements UserRegisterExtPt {
    @Override
    public void validate(String userName) {
        if (userName.length() > 10) {
            throw new BizException("普通用户名长度不能超过10");
        }
    }

    @Override
    public void afterRegister(String userName) {
        System.out.println("发送欢迎邮件给普通用户:" + userName);
    }
}

场景 B:VIP 用户实现

codeJava

复制代码
@Extension(bizId = "VIP_USER") // 标记业务身份 ID
public class VipUserRegisterExt implements UserRegisterExtPt {
    @Override
    public void validate(String userName) {
        // VIP 用户特权:名字可以很长,不做限制
        // 仅做简单的敏感词过滤
    }

    @Override
    public void afterRegister(String userName) {
        System.out.println("增加VIP积分并分配专属客服给:" + userName);
    }
}
第三步:在业务编排中调用扩展点(App层)

回到我们的 UserRegisterCmdExe(命令执行器)。现在,我们不再直接写逻辑,而是通过 COLA 提供的 ExtensionExecutor 来分发请求。

codeJava

复制代码
@Component
@CommandHandler
public class UserRegisterCmdExe implements CommandExecutorI<Response, UserRegisterCmd> {

    @Autowired
    private UserGateway userGateway;
    
    @Autowired
    private ExtensionExecutor extensionExecutor; // 注入扩展点执行器

    @Override
    public Response execute(UserRegisterCmd cmd) {
        // 1. 构建业务场景 (BizScenario)
        // 这里的 bizId 通常来自前端参数 cmd.getUserType(),例如 "VIP_USER" 或 "COMMON_USER"
        BizScenario scenario = BizScenario.valueOf(cmd.getUserType());

        // 2. 执行扩展点:校验逻辑
        // executeVoid 方法会自动根据 scenario 找到对应的实现类 (Common 或 Vip) 并执行
        extensionExecutor.executeVoid(UserRegisterExtPt.class, scenario, 
            ext -> ext.validate(cmd.getUserName()));

        // 3. 通用逻辑:领域对象转换与密码加密 (所有用户都一样)
        User user = new User();
        user.setUserName(cmd.getUserName());
        user.setPassword(cmd.getPassword());
        user.encryptPassword();

        // 4. 持久化
        userGateway.save(user);
        
        // 5. 执行扩展点:后置处理
        extensionExecutor.executeVoid(UserRegisterExtPt.class, scenario, 
            ext -> ext.afterRegister(cmd.getUserName()));

        return Response.buildSuccess();
    }
}

5.8 总结与实战心得

通过上述的"多身份"实战,我们可以清晰地看到 COLA 架构的威力:

  1. 开闭原则(OCP)的完美体现: 如果未来新增了"企业用户",我们只需要新增一个 EnterpriseUserRegisterExt 类并打上注解,无需修改 UserRegisterCmdExe 中的任何一行代码。系统越复杂,这种优势越明显。

  2. 业务逻辑清晰分层:

    • App Layer:负责流程编排,决定"先做什么,再做什么"(先校验,再保存,再后置处理)。

    • Domain Layer:负责核心模型行为(如密码加密)。

    • Extension:负责处理差异化逻辑(不同用户的特殊规则)。

  3. 避免"大泥球": 所有的 if-else 都被多态取代了,代码的可读性和可维护性得到了质的飞跃。

欢迎关注,一起交流,一起进步~

相关推荐
拾忆,想起1 小时前
Dubbo服务调用失败调试指南:从问题定位到快速修复
前端·微服务·架构·dubbo·safari
存内计算开发者1 小时前
存算一体架构在空间计算中的应用
人工智能·神经网络·机器学习·计算机视觉·架构·空间计算·存算一体
技术传感器1 小时前
Prompt工程的艺术与科学:从“对话“到“编程“,掌握与大模型高效协作的元技能
人工智能·microsoft·架构·prompt·aigc
Gavin在路上1 小时前
架构设计之COLA架构
java·数据库·架构
JienDa3 小时前
JienDa聊PHP:小红书仿站实战深度架构全解析
开发语言·架构·php
im_AMBER10 小时前
Canvas架构手记 05 鼠标事件监听 | 原生事件封装 | ctx 结构化对象
前端·笔记·学习·架构
JienDa10 小时前
JienDa聊PHP:电商实战中主流PHP框架的协同策略与架构优化
开发语言·架构·php
JienDa10 小时前
JienDa聊PHP:起卦、卜卦平台实战中PHP框架的协同架构方略
开发语言·架构·php
a***131410 小时前
Partition架构
架构