具有Spring的簡單工作流引擎

幾個月前,在處理一個公司項目時,我們需要開發REST服務,該服務用于根據客戶端應用程序發送的數據發送電子郵件。 在開發此服務期間,我們決定創建簡單的工作流引擎,該引擎將為發送電子郵件收費,但該引擎也可用于任何類型的簡單流。

在本文中,我將逐步說明如何實現可處理序列流的簡單工作流引擎。

為了實現此工作流引擎,我們使用了spring框架,但是無論使用哪種框架,也可以不使用任何框架,如何在任何框架上實現該想法都應相同。

我們將從對序列工作流模式的簡短介紹開始,然后,我們將研究所需的接口,最后,我們將從使用Spring實現工作流引擎開始。

序列工作流程模式

序列工作流程模式描述了其中每個步驟(動作)一步一步地完成的工作流程。 在下一張圖片上,您可以看到它的外觀:

流中要處理的每個動作都共享相同的上下文,這使流的參與者之間可以共享信息。 使用公共上下文的想法是因為每個步驟都應該彼此獨立,并且應該將它們作為其他流程的一部分輕松添加。

如果要獲取有關序列工作流程模式的更多信息,請訪問: 序列模式 。

定義所需的界面

下一步是創建一組接口,使我們可以輕松創建工作流程并定義工作流程操作。

我們可以從Workflow界面開始。 此接口負責處理工作流程操作,實際上它定義了我們的工作流程引擎應該執行的操作。 這是一個非常簡單的界面,只有一種方法“ processWorkflow”。

此方法由工作流引擎調用,用于為工作流提供可在工作流內部使用的初始對象,它表示每個工作流的起點。

package ba.codecentric.workflow;import java.util.Map;/*** Process email workflow.** @author igor.madjeric**/public interface Workflow {/*** Method for processing workflow.** @param parameters* maps of object which are needed for workflow processing* @return true in case that workflow is done without errors otherwise false*/public boolean processWorkflow(Map<String, Object> parameters);}Next what we need is interface used for defining workflow action. This is also simple interface whit only one method too.package ba.codecentric.workflow;
/*** Define workflow action** @author igor.madjeric**/public interface WorkflowAction {/*** Execute action.** @param context* @throws Exception*/public void doAction(Context context) throws Exception;}So this interface define only doAction method which will be called by workflow implementation.Last interface which we need to define is Context interface. This interface define two methods, one for setting object in context and another for retrieving it.package ba.codecentric.workflow;/*** Context interface.** Class which extend this interface should be able to provide mechanism for keeping object in context.<br />* So they can be shared between action inside workflow.** @author igor.madjeric**/public interface Context {/*** Set value with specified name in context.* If value already exist it should overwrite value with new one.** @param name of attribute* @param value which should be stored for specified name*/public void setAttribute(String name, Object value);/*** Retrieve object with specified name from context,* if object does not exists in context it will return null.** @param name of attribute which need to be returned* @return Object from context or null if there is no value assigned to specified name*/public Object getAttribute(String name);}

這是我們為簡單工作流程需要定義的所有接口

實施簡單的工作流引擎

定義接口后,我們可以從實現工作流引擎開始。 引擎應具備的功能有一些要求。

該引擎應支持順序工作流程,這意味著一個接一個地執行動作。

發動機也應該能夠進動多于一個的流量。

工作流操作應該能夠彼此共享信息。

如我們所見,并沒有很多要求,所以我們應該從實現它開始。

首先,我們可以創建上下文類,該上下文類將用于處理動作之間的信息。 此類實現Context接口,并且不執行其他任何操作。

package ba.codecentric.workflow.impl;import java.util.HashMap;
import java.util.Map;
import ba.codecentric.workflow.Context;/**
* Save states between different workflow action.
*
* @author igor.madjeric
*
*/
public class StandardContext implements Context {private Map<String, Object> context;/*** Create context object based.
*
* @param parameters
*/
public StandardContext(Map<String, Object> parameters) {
if (parameters == null) {
this.context = new HashMap<String, Object>();
} else {
this.context = parameters;
}
}@Override
public Object getAttribute(String name) {
return context.get(name);
}@Override
public void setAttribute(String name, Object value) {
context.put(name, value);
}}

第二步是創建實現Workflow接口的類。 我們稱此類為StandardWorkflow。 除了實現Workflow接口之外,該類還實現了ApplicationContextAware接口,因為需要訪問spring bean存儲庫。 如果您不使用spring,則不需要實現它。

我們已經說過,工作流應該支持一個以上的流程。
因此,可以將一個工作流程的操作定義為一個列表,并且每個列表都應分配一個邏輯名稱。 因此,對于動作注冊,我們可以使用諸如Map <String,List <WorkflowAction >>之類的東西。 首先,我們將看到StandardWorkflow和一個自定義流程的spring bean定義,然后我們將看到StandardWorkflow的實現。

Bean的StandardWorkflow定義:

<bean id='standardWorkflow'class='de.codecentric.oev.external.services.workflow.standard.StandardWorkflow'><property name='workflowActions'><map><!-- <entry key='<CID>_action'><ref bean='<CID>_action'/></entry>--><!-- OEVBS --><entry key='action1_action'><ref bean='action1_action' /></entry><!-- PVN --><entry key='action2_action'><ref bean='action2_action' /></entry><!-- WPV --><entry key='action3_action'><ref bean='action3_action' /></entry></map></property></bean>

從這個bean定義中,我們可以看到我們為每個客戶定義了操作,并且在引用bean中定義了操作列表。

這是其中一個客戶Bean的示例:

<bean id='action1_action' class='java.util.ArrayList'><constructor-arg><!-- List of Actions --><list value-type='ba.codecentric.workflow.WorkflowAction' ><ref local='createEmailAction'/><ref bean='sendEmailAction'/></list></constructor-arg></bean>

現在我們可以看到StandardWorkflow的樣子:

package ba.codecentric.workflow.impl;import java.util.List;import java.util.Map;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import ba.codecentric.workflow.Context;import ba.codecentric.workflow.Workflow;import ba.codecentric.workflow.WorkflowAction;/*** Define standard workflow for sending email.** @see Workflow** @author igor.madjeric**/public class StandardWorkflow implements Workflow,ApplicationContextAware {private final Log LOG = LogFactory.getLog(StandardWorkflow.class);private static final String ACTION = 'action';private Map<String, List<WorkflowAction>> workflowActions;private ApplicationContext applicationContext;/***@see de.codecentric.oev.external.services.workflow.Workflow#processWorkflow(java.util.Map)*/@Overridepublic boolean processWorkflow(String workflofName, Map<String, Object> parameters) {Context context = new StandardContext(parameters);List<WorkflowAction> actions = getWorkflowActions(workflofName);for (WorkflowAction action : actions) {try {action.doAction(context);} catch (Exception e) {StringBuilder message = new StringBuilder(
'Failed to complete action:' + action.toString());message.append('\n');message.append(e.getMessage());LOG.error(message.toString());return false;}}return true;}
private List<WorkflowAction> getWorkflowActions(String actionName) {List<WorkflowAction> actions = workflowActions.get(actionName);if (actions == null || actions.isEmpty()) {LOG.error('There is no defined action for ' + actionName);throw new IllegalArgumentException(
'There is no defined action for ' + actionName);}return actions;}
@Overridepublic void setApplicationContext(ApplicationContext applicationContext)
throws BeansException{
this.applicationContext = applicationContext;}
// Getter/Setterpublic Map<String, List<WorkflowAction>> getWorkflowActions() {return workflowActions;}
public void setWorkflowActions(Map<String, List<WorkflowAction>> workflowActions) {this.workflowActions = workflowActions;}
}

再次您可以看到,這也是一個簡單的類,所有工作都在processWorkflow方法中完成,我們向其提供流程名稱和輸入參數。 此方法使用指定的參數創建Context,然后嘗試加載為指定的流定義的操作,如果存在具有指定名稱的流,它將開始運行流。

如何開始流程

這取決于您的需要。 您可以使用我們這樣的休息服務,也可以使用其他任何機制,例如MBean,預定作業,也可以直接從某些服務中進行呼叫。 您需要做的就是調用processWorkflow方法。

參考:來自ICG Madjeric博客的JCG合作伙伴 Igor Madjeric的Spring提供的簡單工作流引擎 。

翻譯自: https://www.javacodegeeks.com/2012/11/simple-workflow-engine-with-spring.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/371014.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371014.shtml
英文地址,請注明出處:http://en.pswp.cn/news/371014.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

php put 參數,php – 如何在Guzzle 5中發送PUT請求的參數?

根據the manual,The body option is used to control the body of an entity enclosingrequest (e.g., PUT, POST, PATCH).記錄的put’ing方法是&#xff1a;$client new GuzzleHttp\Client();$client->put(http://httpbin.org, [headers > [X-Foo > Bar],body > …

TypeScript學習筆記歸納(持續更新ing)

文章目錄 前言 二、TypeScript的優勢體現在哪里&#xff1f; 1、執行時間上的區別 2、基礎數據類型區別 3、TS優勢 三、TypeScript的關鍵特性 四、TypeScript的類型系統 1、什么是類型注釋&#xff1f; 2、類型系統核心 - 常用類型 1&#xff09; 基本類型&#xff0…

組態王 6.55 啟停plc_永宏PLC在遠程控制系統中的應用

一、行業介紹本遠程控制系統是給石藥集團的下屬子公司設計的一個控制方案。主要是配套GPRS-DTU產品實現遠程plc與plc之間的數據共享。從而達到遠程無線數據寫入控制和讀取監控的目的。二、客戶需求(1) 客戶可以在監控室控制至少2-3公里外的井上兩個水泵的啟動和停止。(2) 客戶可…

Vue表格中,對數據進行轉換、處理

眾所周知&#xff0c;后端從Mysql取出的數據&#xff0c;一般是很難單獨處理某一個Key的數據的&#xff08;需要處理的話&#xff0c;可能會浪費大量的性能。而且對頁面加載時間有很大的影響&#xff09;&#xff0c;所以&#xff0c;從數據庫取出的數據。只能由前端進行處理。…

Java應用程序中的SQL注入

在本文中&#xff0c;我們將討論什么是SQL注入攻擊。 以及它如何影響任何Web應用程序使用后端數據庫。 在這里&#xff0c;我專注于Java Web應用程序。 開放Web應用程序安全項目&#xff08;OWAP&#xff09;列出了SQL注入是Web應用程序的主要漏洞攻擊。 黑客將Web請求中的SQL代…

【轉】ReactNativeweexDeviceOne對比

React Native出來有一段時間了&#xff0c;國內的weex和deviceone是近期發布的&#xff0c;我可以說從2011年就開始關注快速開發的跨平臺平臺技術了&#xff0c;接觸過phoneGap、數字天堂、appcan等早期的移動中間件技術&#xff0c;也跟朋友也討論過這類的輕量級框架。這些年通…

bluetooth射頻已關閉請打開bluetooth射頻_希杰大功率射頻放大器燒了維修診斷步驟...

如果電阻值過低&#xff0c;說明電源內部存在短路&#xff0c;正常時其阻值應能達到100千歐以上;電容器應能夠充放電&#xff0c;如果損壞&#xff0c;則表現為AC電源線兩端阻值低&#xff0c;呈短路狀態&#xff0c;否則可能是開關管擊穿。然后檢查直流輸出部分脫開負載&#…

java中整數如何表示,在Java中如何在位級別上內部表示整數?

慕瓜9086354Java整數為32位&#xff0c;并且總是帶符號的。這意味著&#xff0c;最高有效位(MSB)用作符號位。用an表示的整數int不過是位的加權和。權重分配如下&#xff1a;Bit# Weight31 -2^3130 2^3029 2^29... ...2 2^21 2^10 …

洛谷-P1160 隊列安排

題目 Problem Description 一個學校里老師要將班上N個同學排成一列&#xff0c;同學被編號為1&#xff5e;N&#xff0c;他采取如下的方法&#xff1a; 1.先將1號同學安排進隊列&#xff0c;這時隊列中只有他一個人&#xff1b; 2.2&#xff5e;N號同學依次入列&#xff0c;編號…

1.HTML小結

HTML 基本文檔 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>文檔標題</title> </head> <body> 可見文本... </body> </html> <!DOCTYPE html>html文件聲明。charset"UTF-8…

方法參數名稱和Spring

繼續之前的博客文章有關構造函數和方法參數以及Java在運行時不保留參數名稱的情況–先前的文章涉及構造函數不保留參數名稱及其對Spring中的Contructor注入的含義&#xff0c;在此我將介紹更多內容不保留參數名稱的情況對Spring有影響&#xff1a; 1.考慮帶參數的Spring MVC C…

Fragment Or DialogFragment Can not perform this action after onSaveInstanceState

轉載&#xff1a;http://blog.csdn.net/chenshufei2/article/details/48747149 public void show(FragmentManager manager, String tag) {mDismissed false;mShownByMe true;FragmentTransaction ft manager.beginTransaction();ft.add(this, tag);ft.commit(); //注意這里…

php延遲更新,ThinkPHP開發指南-模型-高級模型之延遲更新

導航&#xff1a;上一頁我們經常需要給某些數據表添加一些需要經常更新的統計字段&#xff0c;例如用戶的積分、文件的下載次數等等&#xff0c;而當這些數據更新的頻率比較頻繁的時候&#xff0c;數據庫的壓力也隨之增大不少&#xff0c;我們可以利用高級模型的延遲更新功能緩…

three.js制作3d模型工具_3D打印模型打磨拋光常用工具

對于追求更好模型品質的人來說&#xff0c;對3D打印模型進行后處理工作是必不可少的&#xff0c;而后處理&#xff0c;首要的便是對模型進行打磨、拋光&#xff0c;將不屬于模型的耗材去除&#xff0c;提高表面光潔度。在此工作中&#xff0c;我們需要用到很多工具&#xff0c;…

Linux中文檔去掉windows文本的多余的回車符(^M)

1) 使用sed 去掉windows下的回車符 &#xff08;注意^M 在linux 下寫法 按^M 是回車換行符,輸入方法是按住CTRLv,松開v,按m)sed -i s/^M//g filename 2) 在vim下類似 :%s/^M//g &#xff08;^M輸入方法和上面方法相同&#xff09; 3) 使用dos2unix dos2unix filename 個人覺得第…

為何要清除浮動?如何清除?

原因&#xff1a; 元素設置了float屬性后&#xff0c;就會脫離文檔流&#xff0c;當 包含框 的高度小于 浮動框 的時候&#xff0c;會出現高度塌陷。因此才需要清除浮動&#xff01; 表現如圖&#xff1a;包括框container已經包不住float的圖片了&#xff01; 清除浮動方法&a…

Spring MVC錯誤處理示例

這篇文章描述了在Spring MVC 3中執行錯誤處理的不同技術。該代碼在GitHub上的Spring-MVC-Error-Handling目錄中可用。 它基于帶有注釋的Spring MVC示例。 在Spring 3之前處理異常 在Spring 3之前&#xff0c;使用HandlerExceptionResolvers處理異常。 此接口定義一個方法&…

PLSQL 學習之路(1)創建用戶,表空間,表,數據

1.用SYS用戶登錄PL/SQL SYSXE as SYSDBA 2.創建表空間 create tablespace Mars datafile F:\oracle\Mars.dbf size 500M autoextend on next 100M maxsize unlimited logging extent management local autoallocate segment space management auto; 3.創建用戶 create user Mar…

php數字取反,[轉+自]關于PHP7的新特性(涉及取反和disabled_functions繞過)

PHP7和PHP5上的安全區別preg_replace()不再支持/e修飾符利用\e修飾符執行代碼的后門大家也用了不少了&#xff0c;具體看官方的這段描述:如果設置了這個被棄用的修飾符&#xff0c; preg_replace() 在進行了對替換字符串的 后向引用替換之后, 將替換后的字符串作為php 代碼評估…

如何關閉蘋果手機自動扣費_教你關閉蘋果手機系統的自動更新功能,舊手機還能再用幾年!...

大家都知道&#xff0c;蘋果手機在更新幾個大版本后&#xff0c;手機不是變得非常卡&#xff0c;就是非常的耗電&#xff0c;大大的縮短了手機的使用壽命。所以&#xff0c;許多人都不會選擇更新系統&#xff0c;但是手機只要連上WiFi并且在充電狀態&#xff0c;就會在半夜自動…