一.JAVA 中责任链的实现(一)
该责任链采用可配置方式,选取责任链执行节点,并且支持链路中存在异步流程
1.业务接口api
package com.zhuque.springcloudweb.chain.api;
import com.zhuque.springcloudweb.chain.bean.AsyncCallBackRequest;
import com.zhuque.springcloudweb.chain.bean.SyncRequest;
public interface ProcessApi {
/**
* 同步请求流程
* @param request
*/
public void syncReq (SyncRequest request);
/**
* 异步回调
* @param request
*/
public void asyncCallBack(AsyncCallBackRequest request);
}
2.流程实现
package com.zhuque.springcloudweb.chain.api.impl;
import com.zhuque.springcloudweb.chain.NextProcessServiceFactory;
import com.zhuque.springcloudweb.chain.ProcessService;
import com.zhuque.springcloudweb.chain.api.ProcessApi;
import com.zhuque.springcloudweb.chain.bean.AsyncCallBackRequest;
import com.zhuque.springcloudweb.chain.bean.NextChainContants;
import com.zhuque.springcloudweb.chain.bean.NextProcessDealData;
import com.zhuque.springcloudweb.chain.bean.SyncRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ProcessApiImpl implements ProcessApi {
@Autowired
private NextProcessServiceFactory factory;
@Override
public void syncReq(SyncRequest request) {
// 获取流程 0,2,8
// 组装数据 -- 转换成 NextProcessDealData
// 获取服务
ProcessService processService = factory.getProcessService("0");
factory.executeProcess(new NextProcessDealData());
}
@Override
public void asyncCallBack(AsyncCallBackRequest request) {
// 根据流水信息获取当前流程
// 组装数据 -- 转换成 NextProcessDealData
NextProcessDealData nextProcessDealData = new NextProcessDealData();
// 设置状态为异步回调
nextProcessDealData.setReqType(NextChainContants.ReqType.ASYNC_REQ);
// 获取服务
ProcessService processService = factory.getProcessService("5");
factory.executeProcess(nextProcessDealData);
}
private NextProcessDealData convertNextSynProcessDealData (SyncRequest request) {
return new NextProcessDealData();
}
}
3.异步请求入参
package com.zhuque.springcloudweb.chain.bean;
import lombok.Data;
@Data
public class AsyncCallBackRequest {
private String applyNo;
}
4.同步请求入参
package com.zhuque.springcloudweb.chain.bean;
import lombok.Data;
@Data
public class SyncRequest {
String applyNo;
}
4.责任链上线文基类
package com.zhuque.springcloudweb.chain.bean;
import lombok.Data;
import java.io.Serializable;
@Data
public class ChainBean implements Serializable {
/**
* 责任链 是否执行
*/
private Boolean doProcess = true;
/**
* 流程编号
*/
private String processIds;
/**
* 请求类型
*/
private String reqType;
/**
* 当前程序执行节点
*/
private String proocessId;
}
5.责任链业务数据类
package com.zhuque.springcloudweb.chain.bean;
import lombok.Data;
@Data
public class NextProcessDealData extends ChainBean {
}
6.链路执行描述枚举类
package com.zhuque.springcloudweb.chain.bean;
/**
* 责任链描述
*/
public enum ChainDescribeEnum {
FIRST_PROCESS ("1","流程一"),
SECOND_PROCESS("2","流程二"),
THIRD_PROCESS("3","流程三"),
;
private String processId;
private String describe;
ChainDescribeEnum(String processId, String describe) {
this.processId = processId;
this.describe = describe;
}
public static String getDescribe (String processId) {
for (ChainDescribeEnum chainEnum: ChainDescribeEnum.values() ) {
if (chainEnum.processId .equals(processId)) {
return chainEnum.describe;
}
}
return null;
}
}
7.字符常量池
package com.zhuque.springcloudweb.chain.bean;
public class NextChainContants {
public static String FIRST_PROCESS = "1";
public static String SECOND_PROCESS = "2";
public static String THIRD_PROCESS = "3";
public static class ReqType {
/**
* 同步请求
*/
public static final String SYNC_REQ = "0";
/**
* 异步请求
*/
public static final String ASYNC_REQ = "1";
}
}
8.责任链接口
package com.zhuque.springcloudweb.chain;
import com.zhuque.springcloudweb.chain.bean.NextProcessDealData;
public interface ProcessService {
/**
* 执行流程
* @param processDealData
* @return
*/
ProcessService processDeal(NextProcessDealData processDealData);
/**
* 获取当前节点编号
* @return
*/
String getProcessId();
/**
* 获取下一节点编号
* @return
*/
String getNextProcessId();
}
9.工厂类:该类包括节点数据收集,链路驱动
package com.zhuque.springcloudweb.chain;
import com.zhuque.springcloudweb.chain.bean.NextProcessDealData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
*InitializingBean接口为bean提供了初始化方法的方式,
* 它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法
*
* ApplicationContextAware: 通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware
* 接口中的setApplicationContext方法,可以通过这个上下文环境对象得到Spring容器中的Bean
*/
@Slf4j
@Component
public class NextProcessServiceFactory implements InitializingBean, ApplicationContextAware {
private ApplicationContext applicationContext;
/**
* map存储当前流程
*/
private static Map<String,ProcessService> processServiceMap = new ConcurrentHashMap<>();
/**
* 获取流程执行
* @param processId
*/
public ProcessService getProcessService(String processId){
if (StringUtils.isEmpty(processId)) {
return null;
}
ProcessService processService = processServiceMap.get(processId);
if (processService == null) {
log.info("无此流程编号 : {}",processId);
throw new IllegalArgumentException("流程编号服务不存在");
}
return processService;
}
/**
* 程序执行器-- 链式驱动
* @param processDealData
*/
public void executeProcess (NextProcessDealData processDealData) {
log.info ("【责任链流程开始】");
ProcessService processService = getProcessService(processDealData.getProocessId());
while(true) {
if (null == processService) {
log.info("【责任链流程结束】");
break;
}
processService = processService.processDeal(processDealData);
}
}
@Override
public void afterPropertiesSet() throws Exception {
Map<String, ProcessService> map = applicationContext.getBeansOfType(ProcessService.class);
if (!CollectionUtils.isEmpty(map)) {
map.forEach((k,v)->{
processServiceMap.put(v.getProcessId(),v);
});
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
10.链路节点抽象类:该节点提供统一流水信息处理,统一异常处理等功能
package com.zhuque.springcloudweb.chain;
import com.zhuque.springcloudweb.chain.bean.ChainDescribeEnum;
import com.zhuque.springcloudweb.chain.bean.NextChainContants;
import com.zhuque.springcloudweb.chain.bean.NextProcessDealData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@Slf4j
public abstract class AbstractProcess implements ProcessService {
@Autowired
private NextProcessServiceFactory factory;
@Override
public ProcessService processDeal (NextProcessDealData processDealData) {
String nextProcessId = null;
if (!continued(processDealData.getProcessIds())) {
return factory.getProcessService(getNextProcessId());
}
try {
log.info("当前执行流程-> {}:{} 【开始】",processDealData.getProcessIds(),ChainDescribeEnum.getDescribe(processDealData.getProcessIds()));
if (NextChainContants.ReqType.SYNC_REQ.equals(processDealData.getReqType())||StringUtils.isEmpty(processDealData.getReqType())) {
nextProcessId = doExecute(processDealData);
} else {
processDealData.setReqType(null);
nextProcessId = doAsyExecute(processDealData);
}
// 更新流程信息 -- 更新主流水表信息
successHandler(processDealData);
} catch(Exception e) {
// 异常处理
exceptionHandler(processDealData ,e);
}
ProcessService processService = factory.getProcessService(nextProcessId);
return processService;
}
private Boolean continued(String processIds) {
if (StringUtils.isEmpty(processIds)) {
return false;
}
if (processIds.contains(getProcessId())) {
return true;
}
return false;
}
/**
* 流程成功处理器
* @param processDealData
*/
private final void successHandler(NextProcessDealData processDealData){
log.info("当前执行流程-> {}:{} 【结束】",processDealData.getProcessIds(),ChainDescribeEnum.getDescribe(processDealData.getProcessIds()));
}
/**
* 流程失败处理
* @param processDealData
* @param e
*/
private final void exceptionHandler(NextProcessDealData processDealData, Exception e) {
log.info("流程 : {},{},异常,异常信息 : {}",processDealData.getProcessIds(),ChainDescribeEnum.getDescribe(processDealData.getProcessIds()),e);
throw new RuntimeException("流程执行异常");
}
/**
* 同步请求
* @param processDealData
* @return
*/
public abstract String doExecute(NextProcessDealData processDealData);
/**
* 异步请求
* @param processDealData
* @return
*/
public abstract String doAsyExecute (NextProcessDealData processDealData);
}
11.同步链式子节点1
package com.zhuque.springcloudweb.chain.impl;
import com.zhuque.springcloudweb.chain.AbstractProcess;
import com.zhuque.springcloudweb.chain.bean.NextChainContants;
import com.zhuque.springcloudweb.chain.bean.NextProcessDealData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class NextFirstProcess extends AbstractProcess {
@Override
public String doExecute(NextProcessDealData processDealData) {
log.info("第一层链式流程。。。同步请求");
return getNextProcessId();
}
@Override
public String doAsyExecute(NextProcessDealData processDealData) {
log.info ("第一层链式流程。。。。异步请求");
return null;
}
@Override
public String getProcessId() {
return NextChainContants.FIRST_PROCESS;
}
@Override
public String getNextProcessId() {
return NextChainContants.SECOND_PROCESS;
}
}
12.异步链式字节点
package com.zhuque.springcloudweb.chain.impl;
import com.zhuque.springcloudweb.chain.AbstractProcess;
import com.zhuque.springcloudweb.chain.bean.NextChainContants;
import com.zhuque.springcloudweb.chain.bean.NextProcessDealData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class NextSecondProcess extends AbstractProcess {
@Override
public String doExecute(NextProcessDealData processDealData) {
log.info("方法实现类二,用于异步");
return null;
}
@Override
public String doAsyExecute(NextProcessDealData processDealData) {
return null;
}
@Override
public String getProcessId() {
return NextChainContants.SECOND_PROCESS;
}
@Override
public String getNextProcessId() {
return NextChainContants.THIRD_PROCESS;
}
}