下面举一个流程的例子
@Bean
public IntegrationFlow sample1Definition(IntegrationFlow defaultFlow,
IntegrationFlow aFlow,
IntegrationFlow bFlow,
IntegrationFlow cFlow
) {
//业务幂等性判断
return IntegrationFlows.from("hotelFulfillmentChannel")
.enrichHeaders(h -> h.messageProcessor(payloadAddHeader("path")))
.route("headers['path']", m ->
m.subFlowMapping("a", sf-> sf.gateway(aFlow))
.subFlowMapping("b", sf-> sf.gateway(bFlow))
.subFlowMapping("c", sf-> sf.gateway(cFlow))
.defaultSubFlowMapping(sf -> sf.gateway(defaultFlow))
)
.channel("hotelOutChannel")
.get()
;
}
这是一个简单的流程从hotelFulfillmentChannel 获取数据源,将payload里的字符串放到header里是path, 根据header里path值,路由到a、b、c 路由, 然后路由到aFlow,bFlow,cFlow,3个子流程。最后结果输出到一个hotelOutChannel 管道结束。
每加一个path值,就要先加一个subFlowMapping。在某些情况下,我想不改动flow流程,流程能自己注册到route里,因为我没有完全动态的需要,在写代码的时候其实都已经定下来流程怎么样,只是我想遵守开闭原则,这个流程没有变化就不要动,改变的都集中要一起,防止分散化改动。
所以下面实现一个启动自注册的route
package com.r.travel.flow;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.RouterSpec;
import org.springframework.integration.router.ExpressionEvaluatingRouter;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
@Component
public class FlowRouterSpec {
private static final String DEFAULT_FLOW = "default";
private final Map<String, IntegrationFlow> fulfillmentTryOrderFlowMappings = new ConcurrentHashMap<>();
public FlowRouterSpec(IntegrationFlow defaultFlow) {
fulfillmentTryOrderFlowMappings.put(DEFAULT_FLOW, defaultFlow);
}
public void registerRoute(String routeKey, IntegrationFlow subFlow) {
fulfillmentTryOrderFlowMappings.put(routeKey, subFlow);
}
// 获取注册的RouterSpec供其他地方使用
public Consumer<RouterSpec<String, ExpressionEvaluatingRouter>> getRouterSpec() {
return spec -> {
fulfillmentTryOrderFlowMappings.forEach((key, flow) ->
spec.subFlowMapping(key, sf -> sf.gateway(flow)));
// 可选:设置默认路由
spec.defaultSubFlowMapping(sf -> sf.gateway(fulfillmentTryOrderFlowMappings.get(DEFAULT_FLOW)));
};
}
}
首先实现一个缓存routePath和Integration的map,用于注册上报的缓存。
实现registerRoute方法,用于注册到map中,每个实现类启动调用。
最后getRouterSpec是给主流程的route方法内使用,获取所有routeSpec。
下面是抽象类
public interface FlowFactory {
void registerRouter();
IntegrationFlow getFlow();
}
package com.r.travel.flow;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Slf4j
@Component
public class AFlowFactory implements FlowFactory{
@Autowired
private FlowRouterSpec flowRouterSpec;
@PostConstruct
public void init(){
registerRouter();
}
@Override
public void registerRouter() {
String routerKey = "a";
flowRouterSpec.registerRoute(routerKey, getFlow());
}
@Override
public IntegrationFlow getFlow() {
return f-> f.handle(
(p,v)-> {
log.info("dynamic a flow");
return p;
}
).logAndReply();
}
}
某个实现类,使用PostConstruct启动注册,调用FlowRouterSpec的registerRouter方法。
@Bean
public IntegrationFlow sampleDynamicDefinition(FlowRouterSpec flowRouterSpec) {
return IntegrationFlows.from("hotelFulfillmentChannel")
.enrichHeaders(h -> h.messageProcessor(payloadAddHeader("path")))
.route("headers['path']", flowRouterSpec.getRouterSpec())
.channel("hotelOutChannel")
.get()
;
}
最终主流程实现。
参考例子
https://github.com/R-Richie/R-development-lab/tree/main/lefox-travel-example/src/main/java/com/r/travel/controller
https://github.com/R-Richie/R-development-lab/tree/main/lefox-travel-example/src/main/java/com/r/travel/flow
Sample1Flow、FlowRouterSpec、FlowFactory、AFlowFactory、BFlowFactory、CFlowFactory