All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yomahub.liteflow.core.NodeComponent Maven / Gradle / Ivy

The newest version!
/**
 * 

Title: liteflow

*

Description: 轻量级的组件式流程框架

* @author Bryan.Zhang * @email [email protected] * @Date 2020/4/1 */ package com.yomahub.liteflow.core; import cn.hutool.core.date.StopWatch; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.core.proxy.LiteFlowProxyUtil; import com.yomahub.liteflow.enums.CmpStepTypeEnum; import com.yomahub.liteflow.enums.NodeTypeEnum; import com.yomahub.liteflow.flow.LiteflowResponse; import com.yomahub.liteflow.flow.element.Node; import com.yomahub.liteflow.flow.entity.CmpStep; import com.yomahub.liteflow.flow.executor.DefaultNodeExecutor; import com.yomahub.liteflow.flow.executor.NodeExecutor; import com.yomahub.liteflow.log.LFLog; import com.yomahub.liteflow.log.LFLoggerManager; import com.yomahub.liteflow.monitor.CompStatistics; import com.yomahub.liteflow.monitor.MonitorBus; import com.yomahub.liteflow.slot.DataBus; import com.yomahub.liteflow.slot.Slot; import com.yomahub.liteflow.spi.holder.CmpAroundAspectHolder; import com.yomahub.liteflow.util.JsonUtil; import java.lang.reflect.Method; import java.util.Date; import java.util.List; import java.util.Stack; /** * 普通组件抽象类 * * @author Bryan.Zhang * @author luo yi */ public abstract class NodeComponent{ private final LFLog LOG = LFLoggerManager.getLogger(this.getClass()); private MonitorBus monitorBus; private String nodeId; private String name; private NodeTypeEnum type; // 这是自己的实例,取代this // 为何要设置这个,用this不行么,因为如果有aop去切的话,this在spring的aop里是切不到的。self对象有可能是代理过的对象 private NodeComponent self; // 重试次数 private int retryCount = 0; // 是否重写了rollback方法 private boolean isRollback = false; // 在目标异常抛出时才重试 private Class[] retryForExceptions = new Class[] { Exception.class }; /** 节点执行器的类全名 */ private Class nodeExecutorClass = DefaultNodeExecutor.class; /** 当前对象为单例,注册进spring上下文,但是node实例不是单例,这里通过对node实例的引用来获得一些链路属性 **/ private final ThreadLocal> refNodeStackTL = new ThreadLocal<>(); public NodeComponent() { // 反射判断是否重写了rollback方法 Class clazz = this.getClass(); try { Method method = clazz.getDeclaredMethod("rollback"); if(ObjectUtil.isNotNull(method)){ this.setRollback(true); } } catch (Exception ignored) {} } public void execute() throws Exception { Slot slot = this.getSlot(); // 在元数据里加入step信息 CmpStep cmpStep = new CmpStep(nodeId, name, CmpStepTypeEnum.SINGLE); cmpStep.setTag(this.getTag()); cmpStep.setInstance(this); cmpStep.setRefNode(this.getRefNode()); cmpStep.setStartTime(new Date()); slot.addStep(cmpStep); StopWatch stopWatch = new StopWatch(); stopWatch.start(); try { // 前置处理 self.beforeProcess(); // 主要的处理逻辑 self.process(); // 成功后回调方法 self.onSuccess(); // 步骤状态设为true cmpStep.setSuccess(true); } catch (Exception e) { // 步骤状态设为false,并加入异常 cmpStep.setSuccess(false); cmpStep.setException(e); // 执行失败后回调方法 // 这里要注意,失败方法本身抛出错误,只打出堆栈,往外抛出的还是主要的异常 try { self.onError(e); } catch (Exception ex) { String errMsg = StrUtil.format("component[{}] onError method happens exception", this.getDisplayName()); LOG.error(errMsg, ex); } throw e; } finally { // 后置处理 self.afterProcess(); stopWatch.stop(); final long timeSpent = stopWatch.getTotalTimeMillis(); LOG.info("component[{}] finished in {} milliseconds", this.getDisplayName(), timeSpent); cmpStep.setEndTime(new Date()); // 往CmpStep中放入时间消耗信息 cmpStep.setTimeSpent(timeSpent); // 性能统计 if (ObjectUtil.isNotNull(monitorBus)) { CompStatistics statistics = new CompStatistics(this.getClass().getSimpleName(), timeSpent); monitorBus.addStatistics(statistics); } } } public void doRollback() throws Exception { Slot slot = this.getSlot(); boolean alreadyRollback = slot.getRollbackSteps().stream().anyMatch(cmpStep -> cmpStep.getRefNode().equals(getRefNode())); if (alreadyRollback){ return; } CmpStep cmpStep = new CmpStep(nodeId, name, CmpStepTypeEnum.SINGLE); cmpStep.setTag(this.getTag()); cmpStep.setInstance(this); cmpStep.setRefNode(this.getRefNode()); slot.addRollbackStep(cmpStep); StopWatch stopWatch = new StopWatch(); stopWatch.start(); try { self.rollback(); } catch (Exception e) { throw e; } finally { stopWatch.stop(); final long timeSpent = stopWatch.getTotalTimeMillis(); LOG.info("component[{}] rollback in {} milliseconds", this.getDisplayName(), timeSpent); // 往CmpStep中放入时间消耗信息 cmpStep.setRollbackTimeSpent(timeSpent); } } public void beforeProcess() { // 全局切面只在spring体系下生效,这里用了spi机制取到相应环境下的实现类 // 非spring环境下,全局切面为空实现 CmpAroundAspectHolder.loadCmpAroundAspect().beforeProcess(this.self); } public abstract void process() throws Exception; public void rollback() throws Exception{ // 如果需要失败后回滚某个方法,请覆盖这个方法 }; public void onSuccess() throws Exception { // 如果需要在成功后回调某一个方法,请覆盖这个方法 // 全局切面只在spring体系下生效,这里用了spi机制取到相应环境下的实现类 // 非spring环境下,全局切面为空实现 CmpAroundAspectHolder.loadCmpAroundAspect().onSuccess(this.self); } public void onError(Exception e) throws Exception { // 如果需要在抛错后回调某一段逻辑,请覆盖这个方法 // 全局切面只在spring体系下生效,这里用了spi机制取到相应环境下的实现类 // 非spring环境下,全局切面为空实现 CmpAroundAspectHolder.loadCmpAroundAspect().onError(this.self, e); } public void afterProcess() { CmpAroundAspectHolder.loadCmpAroundAspect().afterProcess(this.self); } // 是否进入该节点 public boolean isAccess() { return true; } // 出错是否继续执行 public boolean isContinueOnError() { return false; } // 是否结束整个流程(不往下继续执行) public boolean isEnd() { Boolean isEnd = this.getRefNode().getIsEnd(); if (ObjectUtil.isNull(isEnd)) { return false; }else { return isEnd; } } // 设置是否结束整个流程 public void setIsEnd(boolean isEnd) { this.getRefNode().setIsEnd(isEnd); } public void setIsContinueOnError(boolean isContinueOnError) { this.getRefNode().setIsContinueOnErrorResult(isContinueOnError); } public Integer getSlotIndex() { return this.getRefNode().getSlotIndex(); } public Slot getSlot() { return DataBus.getSlot(this.getSlotIndex()); } public T getFirstContextBean() { return this.getSlot().getFirstContextBean(); } public T getContextBean(Class contextBeanClazz) { return this.getSlot().getContextBean(contextBeanClazz); } public T getContextBean(String contextName) { return this.getSlot().getContextBean(contextName); } public String getNodeId() { return nodeId; } public void setNodeId(String nodeId) { this.nodeId = nodeId; } public NodeComponent getSelf() { return self; } public void setSelf(NodeComponent self) { this.self = self; } public String getName() { return name; } public void setName(String name) { this.name = name; } public NodeTypeEnum getType() { return type; } public void setType(NodeTypeEnum type) { this.type = type; } public void sendPrivateDeliveryData(String nodeId, T t) { this.getSlot().setPrivateDeliveryData(nodeId, t); } public T getPrivateDeliveryData() { return this.getSlot().getPrivateDeliveryData(this.getNodeId()); } public int getRetryCount() { return retryCount; } public void setRetryCount(int retryCount) { this.retryCount = retryCount; } public Class[] getRetryForExceptions() { return retryForExceptions; } public void setRetryForExceptions(Class[] retryForExceptions) { this.retryForExceptions = retryForExceptions; } public Class getNodeExecutorClass() { return nodeExecutorClass; } public void setNodeExecutorClass(Class nodeExecutorClass) { this.nodeExecutorClass = nodeExecutorClass; } public String getTag() { return this.getRefNode().getTag(); } public MonitorBus getMonitorBus() { return monitorBus; } public void setMonitorBus(MonitorBus monitorBus) { this.monitorBus = monitorBus; } public T getRequestData() { return getSlot().getRequestData(); } public T getSubChainReqData() { return getSlot().getChainReqData(this.getCurrChainId()); } public T getSubChainReqDataInAsync() { return getSlot().getChainReqDataFromQueue(this.getCurrChainId()); } public boolean isRollback() { return isRollback; } public void setRollback(boolean rollback) { isRollback = rollback; } /** * @deprecated 请使用 {@link #getChainId()} * @return String */ @Deprecated public String getChainName() { return getSlot().getChainName(); } public String getChainId() { return getSlot().getChainId(); } public String getDisplayName() { if (StrUtil.isEmpty(this.name)) { return this.nodeId; } else { return StrUtil.format("{}({})", this.nodeId, this.name); } } public String getCurrChainId() { return getRefNode().getCurrChainId(); } public Node getRefNode() { return this.refNodeStackTL.get().peek(); } public void setRefNode(Node refNode) { if (this.refNodeStackTL.get() == null){ Stack stack = new Stack<>(); stack.push(refNode); this.refNodeStackTL.set(stack); }else{ Node compareNode = this.refNodeStackTL.get().peek(); if (!compareNode.equals(refNode)) { this.refNodeStackTL.get().push(refNode); } } } public void removeRefNode() { if (this.refNodeStackTL.get().size() > 1) { this.refNodeStackTL.get().pop(); }else{ this.refNodeStackTL.remove(); } } public T getCmpData(Class clazz) { String cmpData = getRefNode().getCmpData(); if (StrUtil.isBlank(cmpData)) { return null; } if (clazz.equals(String.class) || clazz.equals(Object.class)) { return (T) cmpData; } return JsonUtil.parseObject(cmpData, clazz); } public List getCmpDataList(Class clazz) { String cmpData = getRefNode().getCmpData(); if (StrUtil.isBlank(cmpData)) { return null; } return JsonUtil.parseList(cmpData, clazz); } public Integer getLoopIndex() { return this.getRefNode().getLoopIndex(); } public Integer getPreLoopIndex() { return this.getRefNode().getPreLoopIndex(); } public Integer getPreNLoopIndex(int n) { return this.getRefNode().getPreNLoopIndex(n); } public T getCurrLoopObj() { return this.getRefNode().getCurrLoopObject(); } public T getPreLoopObj() { return this.getRefNode().getPreLoopObject(); } public T getPreNLoopObj(int n) { return this.getRefNode().getPreNLoopObject(n); } @Deprecated public void invoke(String chainId, Object param) throws Exception { FlowExecutorHolder.loadInstance().invoke(chainId, param, this.getSlotIndex()); } public LiteflowResponse invoke2Resp(String chainId, Object param) { return FlowExecutorHolder.loadInstance().invoke2Resp(chainId, param, this.getSlotIndex()); } @Deprecated public void invokeInAsync(String chainId, Object param) throws Exception { FlowExecutorHolder.loadInstance().invokeInAsync(chainId, param, this.getSlotIndex()); } public LiteflowResponse invoke2RespInAsync(String chainId, Object param) { return FlowExecutorHolder.loadInstance().invoke2RespInAsync(chainId, param, this.getSlotIndex()); } public T getItemResultMetaValue(Integer slotIndex){ return null; } protected String getMetaValueKey(){ Class originalClass = LiteFlowProxyUtil.getUserClass(this.getClass()); return originalClass.getName(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy