業務視覺化-讓你的流程圖"Run"起來

前言

最近在研究業務視覺化的問題,在日常的工作中,流程圖和程式碼往往是分開管理的。

一個被維護多次的系統,到最後流程圖和程式碼是否匹配這個都很難說。

於是一直有一個想法,讓程式直接讀流程圖,根據流程圖的配置來決定程式執行的順序。

一轉眼三年過去了,目前這個想法已經逐步落地實現變成程式碼。

問題

對於簡單的流程

a -> b -> c

可以很容易用程式碼來實現

// 執行aa();// 執行bb();// 執行cc();

對於並行的流程

a -> ba -> c

這個就要多執行緒框架來實現

// 執行aa();// a結束後執行bnew Thread(b)。start();// a結束後執行cnew Thread(c)。start();

對於分支合併的流程

a -> ba -> cb -> dc -> d

程式會變得更加複雜

// 執行aa();// a結束後執行bnew Thread(b)。start();// a結束後執行cnew Thread(c)。start();// 等待b,c結束waitComplete(b,c);// 執行dd();

這個是最常用的業務流程,在實際寫程式的時候,一般會避開多執行緒框架,往往被簡單寫成:

a();b();c();d();

去除了Fork-Join的麻煩,也沒有改變業務執行順序,但和流程圖稍有出入。

於是想到能不能有個框架來控制a,b,c,d的執行順序呢?

也就我們只需要編寫a,b,c,d的單體,執行順序變成可配置。

調查

於是想到各種工作流框架和job執行框架可以滿足這個需求,但是太重了。

為了簡單的需求,引入龐大的工作流或者job執行引擎,無疑是每個專案都不能接受的。

於是,決定手寫一個輕量的,即可以控制程式執行流程,又可以透過圖形介面編輯程式流程的框架。

實現

首先要有一個繪製流程圖的介面。並且能夠將流程圖轉化為json格式。

這裡我選擇了Vis。js的network。

可以編輯簡單流程,如下

業務視覺化-讓你的流程圖

還可以實現流程圖和json之間的互轉。

業務視覺化-讓你的流程圖

業務視覺化-讓你的流程圖

我們把這些節點的基本資訊拿到,就可以得到一張圖,然後透過程式遍歷這張圖的每個節點,即可達到執行流程圖的效果。

接下來就是流程圖的節點與Java的方法綁定了。

我做了一個Annotation來繫結流程圖節點,

public @interface Node {String id() default “” ;String label() default “” ;}

節點得到執行開始事件後,拿到要執行的節點ID和名稱,查詢對應的類的Annotation對應的方法,如找到則執行該方法。

public int execute(String flowId, String nodeId, String historyId, HistoryNodeEntity nodeEntity) throws Exception{String nodeName = nodeEntity。getNodeName();System。out。println( “execute:” + nodeId);System。out。println( “node name:” + nodeEntity。getNodeName());Method methods[] = this 。getClass()。getMethods();if (methods != null ) {for (Method method:methods) {Node node = method。getAnnotation(Node。 class );if (node != null ) {if (node。id()。equals(nodeId) || node。label()。equals(nodeName)) {try {method。invoke( this );return 0 ;} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {e。printStackTrace();throw e;}}}}}return 0 ;}

使用方法

我們需要做一個繼承自FlowRunner的類,裡面的方法和flow的節點繫結,和一個flow的配置檔案,放在相同的目錄下。

業務視覺化-讓你的流程圖

MyFlow1。java

public class MyFlow1 extends FlowRunner {@Node (label= “a” )public void process_a() {System。out。println( “processing a” );}@Node (label= “b” )public void process_b() {System。out。println( “processing b” );}@Node (label= “c” )public void process_c() {System。out。println( “processing c” );}@Node (label= “d” )public void process_c() {System。out。println( “processing d” );}}

MyFlow1。json

{“flowId” : “123” ,“nodes” : [{“id” : “1” ,“label” : “start”},{“id” : “2” ,“label” : “a”},{“id” : “0b5ba9df-b6c7-4752-94e2-debb6104015c” ,“label” : “b”},{“id” : “29bc32c7-acd8-4893-9410-e9895da38b2e” ,“label” : “c”}],“edges” : [{“id” : “1” ,“from” : “1” ,“to” : “2” ,“arrows” : “to”},{“id” : “078ffa82-5eff-4d33-974b-53890f2c9a18” ,“from” : “1” ,“to” : “0b5ba9df-b6c7-4752-94e2-debb6104015c” ,“arrows” : “to”},{“id” : “90663193-7077-4aca-9011-55bc8745403f” ,“from” : “2” ,“to” : “29bc32c7-acd8-4893-9410-e9895da38b2e” ,“arrows” : “to”},{“id” : “a6882e25-c07a-4abd-907e-e269d4eda0ec” ,“from” : “0b5ba9df-b6c7-4752-94e2-debb6104015c” ,“to” : “29bc32c7-acd8-4893-9410-e9895da38b2e” ,“arrows” : “to”}]}

然後透過下面的程式碼來啟動流程。

MyFlow1 myFlow1 = new MyFlow1();myFlow1。startFlow();

系統關閉時,透過下面的程式碼關閉流程管理器

FlowStarter。shutdown();

執行

正常結束日誌如下

Ready queue thread started。Complete queue thread started。json:{“flowId”:“123”,“nodes”:[{“id”:“1”,“label”:“a”},{“id”:“2”,“label”:“b”},{“id”:“0b5ba9df-b6c7-4752-94e2-debb6104015c”,“label”:“c”},{“id”:“29bc32c7-acd8-4893-9410-e9895da38b2e”,“label”:“d”}],“edges”:[{“id”:“1”,“from”:“1”,“to”:“2”,“arrows”:“to”},{“id”:“078ffa82-5eff-4d33-974b-53890f2c9a18”,“from”:“1”,“to”:“0b5ba9df-b6c7-4752-94e2-debb6104015c”,“arrows”:“to”},{“id”:“90663193-7077-4aca-9011-55bc8745403f”,“from”:“2”,“to”:“29bc32c7-acd8-4893-9410-e9895da38b2e”,“arrows”:“to”},{“id”:“a6882e25-c07a-4abd-907e-e269d4eda0ec”,“from”:“0b5ba9df-b6c7-4752-94e2-debb6104015c”,“to”:“29bc32c7-acd8-4893-9410-e9895da38b2e”,“arrows”:“to”}]}execute:1node name:aprocessing aexecute:2node name:bprocessing bexecute:0b5ba9df-b6c7-4752-94e2-debb6104015cnode name:cprocessing cexecute:29bc32c7-acd8-4893-9410-e9895da38b2enode name:dprocessing dComplete success。json:{“nodes”:[{“id”: “1”,“label”: “a” ,“color”: “#36AE7C”},{“id”: “2”,“label”: “b” ,“color”: “#36AE7C”},{“id”: “0b5ba9df-b6c7-4752-94e2-debb6104015c”,“label”: “c” ,“color”: “#36AE7C”},{“id”: “29bc32c7-acd8-4893-9410-e9895da38b2e”,“label”: “d” ,“color”: “#36AE7C”}],“edges”:[{“id”: “1”,“from”: “1”,“to”: “2”,“arrows”: “to”},{“id”: “078ffa82-5eff-4d33-974b-53890f2c9a18”,“from”: “1”,“to”: “0b5ba9df-b6c7-4752-94e2-debb6104015c”,“arrows”: “to”},{“id”: “90663193-7077-4aca-9011-55bc8745403f”,“from”: “2”,“to”: “29bc32c7-acd8-4893-9410-e9895da38b2e”,“arrows”: “to”},{“id”: “a6882e25-c07a-4abd-907e-e269d4eda0ec”,“from”: “0b5ba9df-b6c7-4752-94e2-debb6104015c”,“to”: “29bc32c7-acd8-4893-9410-e9895da38b2e”,“arrows”: “to”}]}

流程執行結束後,會輸出執行結果和執行後的流程圖狀態。

可以直接將json貼到下面的位置,檢視看結果(

綠色表示正常結束,紅色表示異常結束,白色表示等待執行

)。

業務視覺化-讓你的流程圖

異常結束日誌如下

Ready queue thread started。Complete queue thread started。json:{“flowId”:“123”,“nodes”:[{“id”:“1”,“label”:“a”},{“id”:“2”,“label”:“b”},{“id”:“0b5ba9df-b6c7-4752-94e2-debb6104015c”,“label”:“c”},{“id”:“29bc32c7-acd8-4893-9410-e9895da38b2e”,“label”:“d”}],“edges”:[{“id”:“1”,“from”:“1”,“to”:“2”,“arrows”:“to”},{“id”:“078ffa82-5eff-4d33-974b-53890f2c9a18”,“from”:“1”,“to”:“0b5ba9df-b6c7-4752-94e2-debb6104015c”,“arrows”:“to”},{“id”:“90663193-7077-4aca-9011-55bc8745403f”,“from”:“2”,“to”:“29bc32c7-acd8-4893-9410-e9895da38b2e”,“arrows”:“to”},{“id”:“a6882e25-c07a-4abd-907e-e269d4eda0ec”,“from”:“0b5ba9df-b6c7-4752-94e2-debb6104015c”,“to”:“29bc32c7-acd8-4893-9410-e9895da38b2e”,“arrows”:“to”}]}execute:1node name:aprocessing aexecute:2node name:bprocessing bexecute:0b5ba9df-b6c7-4752-94e2-debb6104015cnode name:cprocessing cjava。lang。reflect。InvocationTargetException at java。base/jdk。internal。reflect。NativeMethodAccessorImpl。invoke0(Native Method) at java。base/jdk。internal。reflect。NativeMethodAccessorImpl。invoke(NativeMethodAccessorImpl。java:62) at java。base/jdk。internal。reflect。DelegatingMethodAccessorImpl。invoke(DelegatingMethodAccessorImpl。java:43) at java。base/java。lang。reflect。Method。invoke(Method。java:566) at io。github。nobuglady。network。fw。FlowRunner。execute(FlowRunner。java:49) at io。github。nobuglady。network。fw。executor。NodeRunner。run(NodeRunner。java:93) at java。base/java。util。concurrent。Executors$RunnableAdapter。call(Executors。java:515) at java。base/java。util。concurrent。FutureTask。run(FutureTask。java:264) at java。base/java。util。concurrent。ThreadPoolExecutor。runWorker(ThreadPoolExecutor。java:1128) at java。base/java。util。concurrent。ThreadPoolExecutor$Worker。run(ThreadPoolExecutor。java:628) at java。base/java。lang。Thread。run(Thread。java:834)Caused by: java。lang。RuntimeException: test at io。github。nobuglady。network。MyFlow1。process_b(MyFlow1。java:16) 。。。 11 morejava。lang。reflect。InvocationTargetException at java。base/jdk。internal。reflect。NativeMethodAccessorImpl。invoke0(Native Method) at java。base/jdk。internal。reflect。NativeMethodAccessorImpl。invoke(NativeMethodAccessorImpl。java:62) at java。base/jdk。internal。reflect。DelegatingMethodAccessorImpl。invoke(DelegatingMethodAccessorImpl。java:43) at java。base/java。lang。reflect。Method。invoke(Method。java:566) at io。github。nobuglady。network。fw。FlowRunner。execute(FlowRunner。java:49) at io。github。nobuglady。network。fw。executor。NodeRunner。run(NodeRunner。java:93) at java。base/java。util。concurrent。Executors$RunnableAdapter。call(Executors。java:515) at java。base/java。util。concurrent。FutureTask。run(FutureTask。java:264) at java。base/java。util。concurrent。ThreadPoolExecutor。runWorker(ThreadPoolExecutor。java:1128) at java。base/java。util。concurrent。ThreadPoolExecutor$Worker。run(ThreadPoolExecutor。java:628) at java。base/java。lang。Thread。run(Thread。java:834)Caused by: java。lang。RuntimeException: test at io。github。nobuglady。network。MyFlow1。process_b(MyFlow1。java:16) 。。。 11 moreComplete error。json:{“nodes”:[{“id”: “1”,“label”: “a” ,“color”: “#36AE7C”},{“id”: “2”,“label”: “b” ,“color”: “#EB5353”},{“id”: “0b5ba9df-b6c7-4752-94e2-debb6104015c”,“label”: “c” ,“color”: “#36AE7C”},{“id”: “29bc32c7-acd8-4893-9410-e9895da38b2e”,“label”: “d” ,“color”: “#E8F9FD”}],“edges”:[{“id”: “1”,“from”: “1”,“to”: “2”,“arrows”: “to”},{“id”: “078ffa82-5eff-4d33-974b-53890f2c9a18”,“from”: “1”,“to”: “0b5ba9df-b6c7-4752-94e2-debb6104015c”,“arrows”: “to”},{“id”: “90663193-7077-4aca-9011-55bc8745403f”,“from”: “2”,“to”: “29bc32c7-acd8-4893-9410-e9895da38b2e”,“arrows”: “to”},{“id”: “a6882e25-c07a-4abd-907e-e269d4eda0ec”,“from”: “0b5ba9df-b6c7-4752-94e2-debb6104015c”,“to”: “29bc32c7-acd8-4893-9410-e9895da38b2e”,“arrows”: “to”}]}摺疊

流程執行結束後,會輸出執行結果和執行後的流程圖狀態。

可以直接將json貼到下面的位置,檢視看結果(

綠色表示正常結束,紅色表示異常結束,白色表示等待執行

)。

業務視覺化-讓你的流程圖

原始碼:https://github。com/nobuglady/nobuglady-network

文章來自https://www。cnblogs。com/nobuglady/p/16423995。html