1. 程式人生 > >流程引擎核心程式碼(Spring核心原理)★★★★★

流程引擎核心程式碼(Spring核心原理)★★★★★

import java.util.HashMap;

/**
 * 每一個流程的全域性上下文(靜態內部類實現的單例)
 *
 * @author wb-zf300458 on 2018/1/30.
 */
public class FlowGlobalContext {
    private ThreadLocal nodeToShareData;

    private static class GlobalContextHolder {
        private static final FlowGlobalContext INSTANCE = new FlowGlobalContext();
    }

    private FlowGlobalContext() {
        nodeToShareData = new ThreadLocal();
        nodeToShareData.set(new HashMap<String,Object>());
    }

    public static final FlowGlobalContext getInstance() {
        return GlobalContextHolder.INSTANCE;
    }

    public ThreadLocal getNodeToShareData(){
        return nodeToShareData;
    }
}
----------------------------------------------------------------------------
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.util.Assert;

/**
 * 單例工廠(單例、單例登錄檔)
 *
 * @author wb-zf300458 on 2018/1/31.
 */
public class AbstractSingleBeanFactory {
    /**
     * 充當了Bean例項的快取,實現方式和單例登錄檔相同
     */
    private final Map singletonCache;

    private AbstractSingleBeanFactory() {
        singletonCache = new ConcurrentHashMap(256);
    }

    private static class AbstractBeanFactoryHolder {
        private static final AbstractSingleBeanFactory INSTANCE = new AbstractSingleBeanFactory();
    }

    public static AbstractSingleBeanFactory getInstance() {
        return AbstractBeanFactoryHolder.INSTANCE;
    }

    public Object getBean(String name) throws Exception{
        Assert.notNull(name, "'name' must not be null");
        Object bean = this.singletonCache.get(name);
        // A與B執行緒同一時刻執行到該地方
        if (bean == null) {
            //使用了程式碼鎖定同步塊,原理和同步方法相似,但是這種寫法效率更高
            // A與B執行緒同一時刻執行到這
            synchronized (this.singletonCache) {
                // A運氣好先執行,B在等待,A處理完畢,會在集合中有name相關的例項,然後B結束等待,進入此程式碼,而此時集合中
                // 有A執行緒執行後放入的例項。所以下面需要再次判斷,防止B執行緒多new 一個例項出來。
                if (bean == null) {
                    bean = this.singletonCache.get(name);
                    if (bean == null) {
                        bean = Class.forName(name).newInstance();
                        this.singletonCache.put(name, bean);
                        return bean;
                    }
                }
            }
        }
        return bean;
    }
}

------------------------------------------------------------------------------

import com.wdk.finance.enums.BizTypeEnum;
import com.wdk.finance.node.flow.AbstractProcessFlow;
import com.wdk.finance.node.factory.bean.AbstractSingleBeanFactory;

/**
 * 流程工廠
 *
 * @author wb-zf300458 on 2018/1/27.
 */
public class FlowFactory {
    /**
     * 
     * @param bizType
     * @return
     */
    public AbstractProcessFlow getProcessFlow(String bizType) throws Exception {
        if (bizType == null) {
            return null;
        }
        if (String.valueOf(4).equals(bizType)) {
            return (AbstractProcessFlow)AbstractSingleBeanFactory.getInstance().getBean("com.wdk.finance.node.flow.PerformanceInvoiceProcessFlow");
        }
        return null;
    }
}
------------------------------------------------------------------------------
import com.wdk.finance.node.AbstractNode;

/**
 *
 *
 * @author wb-zf300458 on 2018/1/26.
 */
public class A extends AbstractNode {

    @Override
    public void execute() throws Exception {

    }
}
------------------------------------------------------------------------------
import com.wdk.finance.node.AbstractNode;

/**
 * 
 *
 * @author wb-zf300458 on 2018/1/25.
 */
public class B extends AbstractNode {

    @Override
    public void execute() throws Exception {

    }
}
------------------------------------------------------------------------------
import com.wdk.finance.node.AbstractNode;
import com.wdk.finance.node.context.FlowGlobalContext;

/**
 * 流程完畢移除該流程執行緒的引數值
 *
 * @author wb-zf300458 on 2018/1/30.
 */
public class RemoveThreadLocalValue extends AbstractNode {
    @Override
    public void execute() throws Exception {
       FlowGlobalContext.getInstance().getNodeToShareData().remove();
    }
}
------------------------------------------------------------------------------
import java.util.ArrayList;
import java.util.List;

import com.wdk.finance.node.AbstractNode;

/**
 * 抽象的處理流程
 *
 * @author wb-zf300458 on 2018/1/27.
 */
public abstract class AbstractProcessFlow implements Flow {
    List<AbstractNode> flowCombinations = new ArrayList<>();
}
------------------------------------------------------------------------------
import java.util.List;

import com.wdk.finance.node.AbstractNode;

/**
 * 流程介面
 *
 * @author wb-zf300458 on 2018/1/27.
 */
public interface Flow {
    /**
     * 獲取流程組合
     *
     * @return
     */
    public List<AbstractNode> getFlowCombination() throws Exception;
}
------------------------------------------------------------------------------
import java.util.List;
import com.wdk.finance.node.AbstractNode;
import com.wdk.finance.node.factory.bean.AbstractSingleBeanFactory;

/**
 * 履約單據處理流程
 *
 * @author wb-zf300458 on 2018/1/27.
 */
public class PerformanceInvoiceProcessFlow extends AbstractProcessFlow{
    @Override
    public List<AbstractNode> getFlowCombination() throws Exception {
        flowCombinations.add((AbstractNode)AbstractSingleBeanFactory.getInstance().getBean("com.wdk.finance.node.flow.biz.A"));
        flowCombinations.add((AbstractNode)AbstractSingleBeanFactory.getInstance().getBean("com.wdk.finance.node.flow.biz.B"));
        flowCombinations.add((AbstractNode)AbstractSingleBeanFactory.getInstance().getBean("com.wdk.finance.node.flow.biz.RemoveThreadLocalValue"));
        return flowCombinations;
    }
}
------------------------------------------------------------------------------
public class MySingleton {
    private static class MySingletonHandler {
        private static MySingleton instance = new MySingleton();
    }

    private MySingleton() {}

    public static MySingleton getInstance() {
        return MySingletonHandler.instance;
    }
}
------------------------------------------------------------------------------
import com.wdk.finance.node.NodeHandler;
import com.wdk.finance.node.factory.bean.AbstractSingleBeanFactory;
import com.wdk.finance.node.factory.flow.FlowFactory;

/**
 * @author wb-zf300458 on 2018/1/31.
 */
public class NodeTest {
    public static void main(String[] args) throws Exception {
        FlowFactory flowFactory = (FlowFactory)AbstractSingleBeanFactory.getInstance().getBean("com.wdk.finance.node.factory.flow.FlowFactory");
        NodeHandler nodeHandler = (NodeHandler)AbstractSingleBeanFactory.getInstance().getBean("com.wdk.finance.node.NodeHandler");
        try {
            nodeHandler.handlerNode(flowFactory.getProcessFlow("4"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
------------------------------------------------------------------------------
import com.wdk.finance.node.factory.bean.AbstractSingleBeanFactory;

/**
 * 測試多執行緒環境下,AbstractSingleBeanFactory建立的物件單例,是否正確
 *
 * @author wb-zf300458 on 2018/2/1.
 */
public class TestAbstractSingleBeanFactory extends Thread {
    @Override
    public void run() {
        try {
            while (true){
                System.out.println(
                    AbstractSingleBeanFactory.getInstance().getBean("com.wdk.finance.node.NodeHandler").hashCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // 測試多執行緒下的
        TestAbstractSingleBeanFactory[] mts = new TestAbstractSingleBeanFactory[1000];
        for (int i = 0; i < mts.length; i++) {
            mts[i] = new TestAbstractSingleBeanFactory();
        }

        for (int j = 0; j < mts.length; j++) {
            mts[j].start();
        }
    }
}
------------------------------------------------------------------------------
import com.wdk.finance.node.context.FlowGlobalContext;

/**
 * 測試多執行緒環境下的靜態內部類實現的單例
 */
public class TestThreadLocal extends Thread{
      
    @Override  
    public void run() {
        FlowGlobalContext.getInstance().getNodeToShareData().set(1);
        while (true){
            FlowGlobalContext globalContext = FlowGlobalContext.getInstance();
            ThreadLocal threadLocal = globalContext.getNodeToShareData();
            Integer i = (Integer)threadLocal.get();
            System.out.println(Thread.currentThread().getName()+","+i);
            if(null != i){
                i++;
            }
            threadLocal.set(i);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
      
    public static void main(String[] args) {
        // 測試多執行緒下的
        TestThreadLocal[] mts = new TestThreadLocal[5];
        for(int i = 0 ; i < mts.length ; i++){
            mts[i] = new TestThreadLocal();
        }

        for (int j = 0; j < mts.length; j++) {
            mts[j].start();
        }
    }  
}  
------------------------------------------------------------------------------
import java.util.Map;

import com.wdk.finance.node.context.FlowGlobalContext;

/**
 * 流程相關的全域性上下文工具類
 *
 * @author wb-zf300458 on 2018/2/1.
 */
public class FlowGlobalContextUtils {

    /**
     * 新增值到全域性map裡面
     *
     * @param key
     * @param value
     */
    public static void put(String key, Object value) {
        ((Map<String, Object>)FlowGlobalContext.getInstance().getNodeToShareData().get()).put(key, value);
    }

    /**
     * 從全域性map裡面取值
     *
     * @param key
     */
    public static Object get(String key) {
        return ((Map<String, Object>)FlowGlobalContext.getInstance().getNodeToShareData().get()).get(key);
    }
}
------------------------------------------------------------------------------
import java.util.Map;
import com.wdk.finance.node.context.FlowGlobalContext;

/**
 * 抽象節點(單例模式)
 *
 * @author wb-zf300458 on 2018/1/25.
 */
public abstract class AbstractNode implements Node {
    /**
     * 節點共享資料
     */
    protected Map<String, Object> nodeToShareData;

    /**
     * 外部呼叫(模板方法)
     * @return
     * @throws Exception
     */
    protected void invoke() throws Exception {
        beforeExecute();
        execute();
    }

    /**
     * 執行目標方法之前
     *
     * @return
     * @throws Exception
     */
    public void beforeExecute()throws Exception{
        // 獲取節點共享的資料
        this.nodeToShareData = (Map<String, Object>)FlowGlobalContext.getInstance().getNodeToShareData().get();
    }
}
------------------------------------------------------------------------------
/**
 * 抽象的節點介面
 *
 * @author by wb-zf300458 on 2018/1/25.
 */
public interface Node {
    /**
     * 執行目標方法
     *
     * @return
     * @throws Exception
     */
    public void execute() throws Exception;
}
------------------------------------------------------------------------------
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.wdk.finance.node.context.FlowGlobalContext;
import com.wdk.finance.node.flow.AbstractProcessFlow;

/**
 * 抽象的節點處理者
 *
 * @author wb-zf300458 on 2018/1/25.
 */
public class NodeHandler {
    public void handlerNode(AbstractProcessFlow abstractProcessFlow) throws Exception{
        // 預設都要執行下一個節點
        ((Map<String, Object>)FlowGlobalContext.getInstance().getNodeToShareData().get()).put("nodeResult", true);
        List<AbstractNode> abstractNodes = abstractProcessFlow.getFlowCombination();
        try{
            Iterator abstractNodesIterator = abstractNodes.iterator();
            while (abstractNodesIterator.hasNext()){
                AbstractNode abstractNode = (AbstractNode)abstractNodesIterator.next();
                abstractNode.invoke();
                // 判斷是否要繼續執行下一個節點
                if (!((Boolean)abstractNode.nodeToShareData.get("nodeResult"))) {
                    if(abstractNodes.size()>1){
                        abstractNodes.get(abstractNodes.size()-1).invoke();
                    }
                    break;
                }
            }
        }catch (Exception e){
            if(abstractNodes.size()>1){
                abstractNodes.get(abstractNodes.size()-1).invoke();
            }
            throw e;
        }
    }
}