COLA開發流程總結

COLA開發流程總結

COLA發起者的博客
COLA是一套用於幫助你實踐DDD落地的項目架構,在開發COLA之前,我們先再熟悉一下基於COLA創建的項目的結構:

image.png

demo-client:

  • api:存放的是對外暴露的接口
  • dto.domainmodel:用來做數據傳輸的輕量級領域對象。
  • to.domainevent: 用來做數據傳輸的領域事件。

demo-app:

  • service:接口實現的facade,沒有業務邏輯,可以包含對不同終端的adapter。
  • eventhandler:處理領域事件,包括本域的和外域的。
  • executor:用來處理命令(Command)和查詢(Query),對複雜業務,可以包含Phase和Step
  • interceptor: COLA提供的對所有請求的AOP處理機制。
  • validator:用來對傳入的命令進行參數校驗。

demo-domain:

  • domain:領域實體。
  • domainservice: 領域服務,用來提供更粗粒度的領域能力。
  • gateway:對外依賴的網關接口,包括存儲、RPC、Search等,可以認爲是對infrastructure的依賴反轉。

demo-infrastructure:

  • config:配置信息相關
  • message:消息處理相關。
  • repository:存儲相關,是gateway的特化,主要用來做本域的數據CRUD操作。
  • gateway:對外依賴的網關接口(demo-domain裏的gateway)的實現。

除此之外,我們還要熟悉一下COLA中關於命名的規範:

命名規範

在COLA架構中,我們也能找到以前熟悉的VO,DTO等對象,只不過在COLA中他們的後綴名變了:

  • VO->CO,COLA中CO對象用於展示給前端。
  • DTO->Cmd,COLA中Cmd對象用於前端和後端的數據交互。
  • Entiry->DO,數據持久化對象。

此外,對於領域對象domain,比如UserDomain,我們在COLA中稱之爲UserE。

如何基於COLA架構實現一個CRUD

在COLA中,比如我們想創建一個User,一套完整的調用鏈大概如下圖所示:

COLA調用鏈

以上是一個經過簡化版的調用鏈,實際的調用鏈還要更復雜,調用過程中可能還包含了多個不同的擴展點(Extension)

查詢

假設我們存在一個名叫組織的實體Organization,我們想實現一個根據主鍵查詢的功能,按照COLA的規範,我們應該現在client中創建對應的接口,比如是OrganizationResource

client:

public interface OrganizationResource {
    /**
     * 根據id查找
     * @param id
     * @return
     */
    @GetMapping(value = "/org/{id}")
    DataResponse<OrganizationCO> get(@PathVariable(value = "id")String id);
}

application:

@RestController
public class OrganizationController implements OrganizationResource {
    /**
     * 根據id查找
     * @param id
     * @return
     */
    @Override
    public DataResponse<OrganizationCO> get(String id) {
        // 不再使用傳統的service做業務查詢,將查詢的邏輯封裝到了對應的領域對象中
        OrganizationE org = OrganizationE.of().id(id);
        return org != null ? DataResponse.of(org.convertToClient())
                : DataResponse.buildFailure(BasicCode.DB_QUERY_NO_RESULT);
    }
}    

domain:

public class OrganizationE {
    public static OrganizationE of() {
        return new OrganizationE();
    }
    
    public OrganizationE id(String id) {
        return getOrganizationGateway().getById(id);
    }
    /**
     * 從對應的gateway中獲取實現
    **/
    private OrganizationGateway getOrganizationGateway() {
        if(this.organizationGateway == null) {
            this.organizationGateway = SpringContextUtil.getBean(OrganizationGateway.class);
        }
        return this.organizationGateway;
    }
}

repostitory:

@Component
public class OrganizationRepository extends RepositorySupport<OrganizationMapper, OrganizationDO> implements OrganizationGateway {
    public OrganizationE getById(String id) {
        OrganizationDO dataObject = super.getById(id);
        return BeanMapper.INSTANCE.copy(dataObject, OrganizationE.class);
    }
}
新增

client:

創建對應的command

注意:command類必須繼承cola提供的Command,否則CommandBus無法發送這些消息給對應的Service處理

@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class OrganizationCreateCmd extends Command {
    /**
     * 名稱
     */
    @NotBlank
    private String name;
    /**
     * 編號,如果沒指定,會根據不同的名稱生成不同的編號,比如liSi會生成1001,zhangSan會生成2001
     */
    private String code;
}

application:

@RestController
public class OrganizationController implements OrganizationResource {
    
    @Autowired
    private OrganizationService orgService;
    
    /**
     * 自定義創建cust1
     * @return
     */
    @PostMapping(value = "/org/cust1/create")
    Response createCust1(@RequestBody OrganizationCreateCmd cmd) {
        cmd.setBizScenario(BizScenario.valueOf(BizScenarioConstant.BIZ_ID.CUST1));
        return orgService.create(cmd);
    }

    /**
     * 自定義創建cust2
     * @return
     */
    @PostMapping(value = "/org/cust2/create")
    Response createCust2(@RequestBody OrganizationCreateCmd cmd) {
        cmd.setBizScenario(BizScenario.valueOf(BizScenarioConstant.BIZ_ID.CUST2));
        return orgService.create(cmd);
    }
}

service

@Service
public class OrganizationService {
    // 注入COLA提供的command bus
    @Autowired
    private CommandBusI cmdBus;

    /**
     * 創建組織
     * 有兩個不同的擴展實現,分別會創建編號爲1001和2001的組織信息
     * @param cmd
     * @return
     */
    public Response create(OrganizationCreateCmd cmd) {
        return cmdBus.send(cmd);
    }
}

extension(擴展點)

public interface OrganizationCreateExtPt extends ExtensionPointI {
    /**
     * 組織創建的擴展點
     * @param cmd
     * @return
     */
    OrganizationE extension(OrganizationCreateCmd cmd);
}

擴展點實現

@Extension(bizId = BizScenarioConstant.BIZ_ID.CUST1)
public class Cust1OrganizationCreateExt implements OrganizationCreateExtPt {
    /**
     * 組織創建的擴展點,根據不同的請求賦予不同的編號
     * @param cmd
     * @return
     */
    @Override
    public OrganizationE extension(OrganizationCreateCmd cmd) {
        // 如果是cust1 賦予1001
        return OrganizationE.of(cmd).setCode("1001");
    }
}
@Extension(bizId = BizScenarioConstant.BIZ_ID.CUST2)
public class Cust2OrganizationCreateExt implements OrganizationCreateExtPt {
    /**
     * 組織創建的擴展點,根據不同的請求賦予不同的編號
     * @param cmd
     * @return
     */
    @Override
    public OrganizationE extension(OrganizationCreateCmd cmd) {
        // 如果是cust2 賦予2001
        return OrganizationE.of(cmd).setCode("2001");
    }
}

擴展點執行器

@Command
public class OrganizationCreateCmdExe implements CommandExecutorI<Response, OrganizationCreateCmd> {
    /**
     * 參數校驗器
     */
    @Autowired
    private OrganizationCreateValidator validator;

    /**
     * 擴展執行器
     */
    @Autowired
    private ExtensionExecutor executor;

    @Override
    public Response execute(OrganizationCreateCmd cmd) {
        // 執行校驗擴展
        executor.executeVoid(OrganizationCreateValidatorExtPt.class,
                cmd.getBizScenario(), exe-> exe.validate(cmd));

        // 執行擴展邏輯
        OrganizationE org = executor.execute(OrganizationCreateExtPt.class,
                cmd.getBizScenario(), exe -> exe.extension(cmd));
        
        // 調用領域對象的create方法
        org.create();
        
        return Response.buildSuccess();
    }
}

domain

public class OrganizationE {
    public OrganizationE create() {
        if(!getOrganizationGateway().create(this)) {
            throw new DBSaveFailedException();
        }
        return this;
    }
}

repository

@Component
public class OrganizationRepository extends RepositorySupport<OrganizationMapper, OrganizationDO> implements OrganizationGateway {

    @Transactional
    public boolean create(OrganizationE organization) {
        OrganizationDO dataObject = BeanMapper.INSTANCE.copy(organization, OrganizationDO.class);
        return super.save(dataObject);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章