You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

六边形架构(Ports and Adapters)复杂业务工作流编排方案咨询

六边形架构下复杂工作流编排的解决方案

问题背景

我正在使用六边形架构(Ports and Adapters)实现复杂业务工作流,但在合理编排工作流方面遇到困难。

业务工作流需求

该工作流需处理以下步骤:

  • REST API 请求触发初始事件
  • 事件存储:持久化事件
  • 决策逻辑:根据事件决定执行单个事件或触发事件链
  • 规则加载:根据事件加载业务规则列表
  • 规则执行:每个规则计算值并持久化结果

对应三个核心用例:

  1. EventHandling:处理入站事件并确定事件链
  2. RuleLoading + Execution:加载适用规则并编排其执行
  3. Specific Rules with Calculation:单个规则执行、值计算及持久化

当前架构困境

在六边形架构中,不确定工作流编排逻辑的放置位置,以及如何在不违反端口适配器原则的前提下协调这三个用例。

已尝试的两种方案及问题

方案1:应用服务编排

@Service 
class EventWorkflowApplicationUseCase( 
    private val eventHandlingUseCase: EventHandlingUseCase, 
    private val ruleLoadingExecutionUseCase: RuleLoadingExecutionUseCase, 
    private val specificRuleCalculationUseCase: SpecificRuleCalculationUseCase ): EventWorkflowPort { 

    override fun processEventWorkflow(request: EventWorkflowCommand): EventWorkflowResult {
        // Step 1: Handle event and determine chain
        val eventChain = eventHandlingUseCase.execute(EventHandlingCommand.from(request))
        
        // Step 2: Load and execute rules
        val ruleResults = ruleLoadingExecutionUseCase.execute(
            RuleLoadingCommand.from(eventChain)
        )
        
        // Step 3: Execute specific rule calculations
        val calculationResults = ruleResults.rules.map { rule ->
            specificRuleCalculationUseCase.execute(
                SpecificRuleCommand.from(rule)
            )
        }
        
        return EventWorkflowResult(calculationResults)
    }
}

问题:应用服务成为处理多关注点的“上帝服务”,直接调用其他用例,违反单一职责原则,导致用例间紧耦合。

方案2:基于端口的组合

// Separate ports for each concern 
interface EventManagementPort { 
    fun storeEvent(command: StoreEventCommand): StoredEvent 
    fun determineEventChain(event: StoredEvent): EventChain
 }  

interface RuleManagementPort { 
    fun loadRules(eventChain: EventChain): List<Rule>
    fun executeRule(rule: Rule): RuleResult 
}  

// Orchestrating application service 
@Service class EventWorkflowApplicationService( 
    private val eventManagement: EventManagementPort, 
    private val ruleManagement: RuleManagementPort ) : EventWorkflowPort {  

        override fun processEventWorkflow(command: EventWorkflowCommand): EventWorkflowResult {  
            val storedEvent = eventManagement.storeEvent(StoreEventCommand.from(command))  
            val eventChain = eventManagement.determineEventChain(storedEvent)  
            val rules = ruleManagement.loadRules(eventChain)  
              
            val results = rules.map { rule ->  
                ruleManagement.executeRule(rule)  
            }  
              
            return EventWorkflowResult(results)  
        }  
}   

问题:产生大量小端口,编排逻辑仍在应用服务中,且可能导致应用服务间调用入站端口,引发循环依赖,违反六边形架构原则。

咨询问题

在六边形架构中,复杂工作流编排逻辑应放置在何处?是否有其他更优方案?恳请提供符合六边形架构原则的工作流处理指导!


符合六边形架构的工作流编排方案

核心思路:将编排逻辑内聚为领域层工作流协调器

六边形架构的核心是领域层与外部隔离,编排逻辑本质是业务流程的一部分,应放在领域层而非应用服务层。通过定义领域服务作为工作流协调器,封装编排逻辑,同时依赖领域端口(而非应用用例或外部端口),保证领域层的独立性。

具体实现步骤

1. 定义领域端口(Domain Ports)

这些端口是领域层对外的依赖抽象,仅暴露领域所需的能力,避免细粒度端口:

// 领域端口:事件持久化与决策
interface EventPersistencePort {
    fun storeEvent(event: DomainEvent): StoredDomainEvent
}

interface EventChainDecisionPort {
    fun determineChain(event: StoredDomainEvent): EventChain
}

// 领域端口:规则加载与执行
interface RuleRepositoryPort {
    fun loadApplicableRules(chain: EventChain): List<BusinessRule>
}

interface RuleExecutionPort {
    fun executeRule(rule: BusinessRule): RuleCalculationResult
}

2. 领域层工作流协调器(Domain Workflow Coordinator)

在领域层创建专门的工作流服务,封装编排逻辑,依赖上述领域端口:

// 领域服务:工作流编排
class EventProcessingWorkflow(
    private val eventPersistence: EventPersistencePort,
    private val chainDecision: EventChainDecisionPort,
    private val ruleRepository: RuleRepositoryPort,
    private val ruleExecutor: RuleExecutionPort
) {
    fun processEvent(eventCommand: InboundEventCommand): WorkflowProcessingResult {
        // 1. 持久化事件(调用领域端口)
        val domainEvent = eventCommand.toDomainEvent()
        val storedEvent = eventPersistence.storeEvent(domainEvent)
        
        // 2. 确定事件链(调用领域端口)
        val eventChain = chainDecision.determineChain(storedEvent)
        
        // 3. 加载规则(调用领域端口)
        val applicableRules = ruleRepository.loadApplicableRules(eventChain)
        
        // 4. 执行规则并收集结果(调用领域端口)
        val calculationResults = applicableRules.map { rule ->
            ruleExecutor.executeRule(rule)
        }
        
        return WorkflowProcessingResult(calculationResults)
    }
}

3. 应用服务层的角色转变

应用服务不再负责编排,仅作为入口适配器与领域层的桥梁,处理请求转换、事务管理等跨领域关注点:

@Service
class EventWorkflowApplicationService(
    private val eventProcessingWorkflow: EventProcessingWorkflow
) : EventWorkflowPort {
    override fun processEventWorkflow(request: EventWorkflowCommand): EventWorkflowResult {
        // 仅做请求转换和调用领域工作流
        val inboundCommand = request.toInboundEventCommand()
        val domainResult = eventProcessingWorkflow.processEvent(inboundCommand)
        
        return domainResult.toApplicationResult()
    }
}

4. 适配器实现领域端口

外部依赖(如数据库、规则引擎)通过适配器实现领域端口,注入到领域工作流中:

// 事件持久化适配器(实现领域端口)
@Repository
class JpaEventPersistenceAdapter : EventPersistencePort {
    override fun storeEvent(event: DomainEvent): StoredDomainEvent {
        // JPA持久化逻辑
    }
}

// 规则执行适配器(实现领域端口)
@Component
class DroolsRuleExecutionAdapter : RuleExecutionPort {
    override fun executeRule(rule: BusinessRule): RuleCalculationResult {
        // Drools规则执行逻辑
    }
}

方案优势

  • 符合六边形架构原则:编排逻辑在领域层,依赖抽象端口,与外部实现完全隔离
  • 单一职责:应用服务仅做请求适配,领域工作流专注于业务流程编排,各端口专注单一能力
  • 低耦合:领域层不依赖外部实现,适配器可独立替换(如换用不同规则引擎)
  • 可测试性:领域工作流可通过Mock领域端口轻松进行单元测试

内容的提问来源于stack exchange,提问作者JavaNullPointer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 02:54:51