spring 工作流引擎_带Spring的简单工作流引擎
spring 工作流引擎
幾個月前,在處理一個公司項目時,我們需要開發(fā)REST服務(wù),該服務(wù)用于根據(jù)客戶端應(yīng)用程序發(fā)送的數(shù)據(jù)發(fā)送電子郵件。 在開發(fā)此服務(wù)期間,我們決定創(chuàng)建簡單的工作流引擎,該引擎將為發(fā)送電子郵件收費,但該引擎也可用于任何類型的簡單流。
在本文中,我將逐步說明如何實現(xiàn)可處理序列流的簡單工作流引擎。
為了實現(xiàn)此工作流引擎,我們使用了spring框架,但是無論使用哪種框架,也可以不使用任何框架,如何在任何框架上實現(xiàn)該想法都應(yīng)相同。
我們將從對序列工作流程模式的簡短介紹開始,然后,我們將研究所需的接口,最后,我們將從使用Spring實現(xiàn)工作流程引擎開始。
序列工作流程模式
序列工作流程模式描述了其中每個步驟(動作)一步一步地完成的工作流程。 在下一張圖片上,您可以看到它的外觀:
流中將要處理的每個動作都共享相同的上下文,這使流的參與者之間可以共享信息。 使用公共上下文的想法是因為每個步驟都應(yīng)該彼此獨立,并且應(yīng)該將它們作為其他流程的一部分輕松添加。
如果要獲取有關(guān)序列工作流程模式的更多信息,請訪問: 序列模式 。
定義所需的界面
下一步是創(chuàng)建一組接口,使我們可以輕松創(chuàng)建工作流程并定義工作流程操作。
我們可以從Workflow界面開始。 該接口負責(zé)處理工作流程操作,實際上它定義了我們的工作流程引擎應(yīng)該執(zhí)行的操作。 這是一個非常簡單的界面,只有一種方法“ processWorkflow”。
此方法由工作流引擎調(diào)用,用于為工作流提供可在工作流內(nèi)部使用的初始對象,它表示每個工作流的起點。
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);}這是我們需要為簡單工作流程定義的所有接口
實施簡單的工作流引擎
定義接口之后,我們可以從實現(xiàn)工作流引擎開始。 引擎應(yīng)具備的功能有一些要求。
該引擎應(yīng)支持順序工作流程,這意味著一個接一個地執(zhí)行動作。
發(fā)動機也應(yīng)該能夠進動多于一個的流量。
工作流操作應(yīng)該能夠彼此共享信息。
如我們所見,并沒有很多要求,所以我們應(yīng)該從實現(xiàn)它開始。
首先,我們可以創(chuàng)建上下文類,該上下文類將用于處理動作之間的信息。 此類實現(xiàn)Context接口,并且不執(zhí)行其他任何操作。
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); }}第二步是創(chuàng)建實現(xiàn)Workflow接口的類。 我們稱此類為StandardWorkflow。 除了實現(xiàn)Workflow接口之外,該類還實現(xiàn)了ApplicationContextAware接口,因為需要訪問spring bean存儲庫。 如果您不使用spring,則不需要實現(xiàn)它。
我們已經(jīng)說過,工作流應(yīng)該支持一個以上的流。
因此,可以將一個工作流程的操作定義為一個列表,并且每個列表都應(yīng)分配一個邏輯名稱。 因此,對于動作注冊,我們可以使用Map <String,List <WorkflowAction >>之類的東西。 首先,我們將看到SpringBean的StandardWorkflow和一個自定義流程的定義,然后我們將看到StandardWorkflow的實現(xiàn)。
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定義中,我們可以看到我們?yōu)槊總€客戶定義了操作,并且在引用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>現(xiàn)在我們可以看到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方法中完成,我們向其提供流程名稱和輸入?yún)?shù)。 此方法使用指定的參數(shù)創(chuàng)建Context,然后嘗試加載為指定流定義的操作,如果存在具有指定名稱的流,它將開始運行流。
如何開始流程
這取決于您的需要。 您可以使用我們這樣的休息服務(wù),也可以使用其他任何機制(例如MBean),計劃的作業(yè),也可以直接從某些服務(wù)中進行呼叫。 您需要做的就是調(diào)用processWorkflow方法。
參考:來自ICG Madjeric博客的JCG合作伙伴 Igor Madjeric的《 Spring的簡單工作流引擎》 。
翻譯自: https://www.javacodegeeks.com/2012/11/simple-workflow-engine-with-spring.html
spring 工作流引擎
總結(jié)
以上是生活随笔為你收集整理的spring 工作流引擎_带Spring的简单工作流引擎的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在家千日好的下一句 在家千日好的下一句是
- 下一篇: 使用React,Spring Boot和