基於Spring的輕量級工做流框架

項目地址

先通俗的介紹一下框架

該框架的靈感來自於現實中的公交系統。公交系統的中最重要的幾個元素,及其對工做流框架的對應:git

  • 乘客:對應工做流框架的中的數據(data)
  • 公交車:數據的載體,
  • 車站:一個車站能夠當作工做流中的一個節點,負責處理「公交車」上的「乘客」。
  • 線路:由哪些節點組成一個完整的工做流的處理鏈
    是否是感受整個公交系統就是一個龐大的工做流處理網,每時每刻都公交車從車站出發,到達一個車站,上下乘客又開往下一個車站(固然前提是不出事故(exception))。

框架中的一些重要接口

BusContext

保存一個業務處理邏輯的上下文環境。github

Bus

一個Bus是保存一次業務流程的上下文環境,業務的起始節點、拋異常的時候怎麼處理等等。一個業務流都會新建一個bus,讓後順着一個一個節點進行處理。框架

Station

Station爲一個業務流(處理鏈)中的一個單獨的節點。這個節點應該是隻依賴於Bus中的上下文環境,根據bus的上下文環境進行處理,而且把處理後的結果(若是有)也放入bus的上下文環境中,供下游的節點使用。 例以下面就是一個Station,從Bus上下文中獲取maxValue和minValue,若是之間的差小於10則設置路由的key爲OK(Routing根據這個進行路由)ide

Routing

因爲Station之間並無直接關聯,所以Routing負責鏈接各個Station,每一個Station都有一個Routing來負責處理bus到底哪一個Station,便可以動態的決定Bus的下一個Station #如何使用spa

舉例子

Station

一個Station就是一個Spring容器管理的Bean(實現了com.lizo.busflow.station.Station接口)。一個station應該是獨立的,有必定通用性的業務處理類,例如一個參數檢查器,ip控制或一個相對對立的業務邏輯等等。.net

public class GetDiff implements Station {
    public void abstractCalculate(@BusParameter("maxValue") int a, @BusParameter("minValue") int b, Bus bus) {
        if (Math.abs(a - b) < 10) {
            bus.setRoutingKey("ok");
        } else {
            bus.setRoutingKey("no");
        }
    }
    @Override
    public String getName() {
        return null;
    }
}

Routing

Routing的必定是要一個對應的Station的,例如能夠在xml配置中,根據路由的key爲進行選擇下一個處理的Station日誌

<!--這個是一個Station-->
   <bean id="getDiff" class="com.lizo.demo.station.GetDiff"></bean>

<!--這個是一個Routing,包含了對應的Station Bean-->
    <bf:stop id="getDiffStop" ref="getDiff" method="abstractCalculate">
        <bf:routing value="ok" to="soutOutOkStop"/>
        <bf:routing value="no" to="soutOutNoStop"/>
    </bf:stop>

注意,code

  • 後面所說的Station默認是指包含了Routing的Bean(bf:stop標籤),並非Station那個Bean
  • 須要ref制定一個Spring bean,使用method制定是由那個method來處理。
  • 默認會使用BusContext的key對應方法的參數名來自動注入,若是有特殊須要,可使用@BusParameter註解,指定BusContext對應的key,是不是必須(默認是必須的,設置爲非必須,會注入默認值)。

Bus

一個完整Bus在xml中定義,以下:xml

<bf:bus id="testBus" start="findMaxStop" maxPath="1000"  exception="exceptionStation" finish="endStation" class="xxx.xxx.xxx.myBus"/>

其中:接口

  • id: 對應的一個Spring Bean的name
  • start: 對應工做流開始Routing
  • maxPath:規定了bus若是處理的次數大於這個數就會跑出異常(防止死循環)
  • exception:指定當發送異常的時候由哪一個Station進行處理,例如一個打錯誤日誌的Station
  • finish:表示當整個流程處理完之後會由哪一個Station最最後處理
  • class:制定bus的類型,若是爲空就使用默認的com.lizo.busflow.bus.DefaultBus

看個DEMO

如今有一個業務需求,須要作如下處理

  1. 輸入一個整型的list
  2. 找出最大值和最小值
  3. 若是最大值和最小值的差大於10輸出「no」,不然輸入「ok」 、 固然真實項目中的業務流程不會這麼簡單,只是這裏使用這個作個例子

第一步 編寫獨立的Station

<bean id="findMax" class="com.lizo.demo.station.FindMax"/>
    <bean id="findMin" class="com.lizo.demo.station.FindMin"/>
    <bean id="soutOutOk" class="com.lizo.demo.station.SoutOutOk"/>
    <bean id="soutOutNo" class="com.lizo.demo.station.SoutOutNo"/>
    <bean id="getDiff" class="com.lizo.demo.station.GetDiff">

例如getDiff的核心代碼以下:

public class GetDiff implements Station {

    public void abstractCalculate(@BusParameter("maxValue") int a, @BusParameter("minValue") int b, BusContext busContext) {

        if (Math.abs(a - b) < 10) {
            busContext.setRoutingKey("ok");
        } else {
            busContext.setRoutingKey("no");
        }
    }

    @Override
    public String getName() {
        return null;
    }

}

把他們串起來吧

<bf:stop id="findMaxStop" ref="findMax" method="doBusiness">
        <bf:routing to="findMinStop"/>
    </bf:stop>

    <bf:stop id="findMinStop" ref="findMin" method="doBusiness">
        <bf:routing to="getDiffStop"/>
    </bf:stop>

    <bf:stop id="getDiffStop" ref="getDiff" method="abstractCalculate">
        <bf:routing value="ok" to="soutOutOkStop"/>
        <bf:routing value="no" to="soutOutNoStop"/>
    </bf:stop>

    <bf:stop id="soutOutOkStop" ref="soutOutOk" method="printOk"/>

    <bf:stop id="soutOutNoStop" ref="soutOutNo" method="printNo"/>

建立一個bus,開車吧司機

<bf:bus id="testBus" start="findMaxStop" />

運行demo

public class DemoApplication {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bus-config.xml");

        Bus testBus = BusFactory.createNewBus("testBus");
        List<Integer> input = Arrays.asList(5, 7, 1, 0, 1, 3, 4, 5, 6, 4);
        testBus.putContext("intList", input);
        testBus.run();


        testBus = BusFactory.createNewBus("testBus");
        input = Arrays.asList(52, 7, 1, -10, 1, 3, 4, 5, 6, 4);
        testBus.putContext("intList", input);
        testBus.run();
    }
}
相關文章
相關標籤/搜索