脚本任务可能是Activiti代码库中“最古老的”类之一,但我认为它仍然未被许多人使用。 (可以理解的?)缺点当然是性能(解释还是编译),并且从IDE角度来看支持较少。

但是,好处(imo)超过了这一点:

  • 脚本在流程xml本身中定义。 无需担心版本控制和类路径上的库问题。
  • 过去我们看到的是,技术水平较低的人不敢尝试脚本。 但是从来没有Java。

无论如何,很少有人知道或已经意识到的是,您可以在Activiti中的脚本中做得很棒,并可以进行一些高级工作。 由于此类脚本是在流程引擎中执行的,因此您可以访问该引擎的所有功能。 是的...一切...这使其既非常强大,又(潜在)危险(如果您不知道自己在做什么)。

让我为您讲解这样的例子。 我喜欢将其称为“定制配置注入”的概念 ,因为它有效地使您可以在运行时添加定制逻辑,从而显着改变流程的执行。 如果您的名字更酷,请告诉我。

所有代码都可以在我的Github页面上找到: https : //github.com/jbarrez/activiti-advanced-scripting

很棒的代码648x303

用例

现在我想做什么。 好吧,我想有一个流程,执行时

  • 向执行的每个用户任务添加“任务完成事件处理程序”
  • 此事件处理程序必须向远程URL触发自定义事件,在该URL上事件处理器可能正在执行其工作

因此,基本上,我们希望在任务完成时将自定义事件触发到某个远程URL。 一个很好的用例是商业智能报告/复杂事件处理,例如使用Esper之类的东西。

Screen-Shot-2013-07-23-at-10.03.112

第一个版本

可以在https://github.com/jbarrez/activit-advanced-scripting/blob/master/src/test/resources/org/activiti/test/my-process.bpmn20.xml中找到该功能的第一版 。 执行此过程时,将发生以下情况:

var config = Context.getProcessEngineConfiguration();
var bpmnParser = config.getBpmnParser();

我们仅获取当前的ProcessEngineConfiguration实例。 我们将从此配置中获取BpmnParser实例,因为我们想更改整个引擎的常规用户任务解析。

接下来,我们构建脚本:

var script = "";
script = script + "importPackage(java.net);";
script = script + "importPackage(java.io);";
script = script + "var url = new URL('http://localhost:8182/echo');";
script = script + "var connection = url.openConnection();";
script = script + "connection.setRequestMethod('POST');";
script = script + "connection.setDoOutput(true);";
script = script + "var outputStream = new BufferedOutputStream(connection.getOutputStream());";
script = script + "outputStream.write(new java.lang.String(\"{'eventType':'task-complete'}\").bytes);";
script = script + "outputStream.flush();";
script = script + "connection.connect();";
script = script + "var respCode = connection.getResponseCode();";
script = script + "if (respCode != 200) ";
script = script + "println('Response code : ' + respCode);";
script = script + "outputStream.close();";
script = script + "connection.disconnect();";

显然,这不是执行此操作的最有效方法,但可以肯定地说明了发生的情况。 消息'eventType:task-complete'通过标准java.net和java.io类发送到localhost:8182 url。

接下来是棘手的部分:

var handler = new ExecuteScriptOnTaskCompleteBpmnParseHandler("JavaScript");
handler.setUserTaskCompleteScript(script);
bpmnParser.getBpmnParserHandlers().addHandler(handler);

// reset the deployment cache such that the new listener gets picked up on a new redeploy
config.getProcessDefinitionCache().clear();

在这里,我们将BpmnParseHandler类添加到引擎配置中。 解析处理程序会将上面定义的脚本的执行添加到引擎发出的“任务完成事件”的每次接收中。 每次对用户任务进行解析时,该解析处理程序都会启动,从而有效地将我们的“将事件发送到远程服务”添加到您的Activiti环境中现在发生的每个用户任务中!

有一个单元测试以了解其工作原理: https : //github.com/jbarrez/activiti-advanced-scripting/blob/master/src/test/java/org/activiti/test/ExecuteScriptInProcessTest.java 。 在测试中,我们设置了一个非常简单的“回显服务”,只要接收到这样的事件,它就会简单地打印出来。 如果在IDE中运行它,您将看到类似以下内容:

Screen-Shot-2013-07-23-at-09.53.00

但是我们可以做得更好

但是我们可以做得更好。 检查以下代码。

var handler = new ExecuteScriptOnTaskCompleteBpmnParseHandler("JavaScript");
handler.setUserTaskCompleteScript("http://localhost:8182/scripts/task-complete.js");
handler.setExecuteScriptInJob(true);
bpmnParser.getBpmnParserHandlers().addHandler(handler);

// Update the configuration to use the correct job handler
var jobHandler = new ExecuteScriptJobHandler();
config.getJobHandlers().put(jobHandler.type,jobHandler);

此代码与上一节中的代码相同。 将“完成”事件的侦听器附加到每个用户任务。 但是,此实现:

  • 异步执行脚本
  • 没有在流程xml中定义脚本,但是它是从远程URL获取的
  • 更新作业处理程序配置

如果您问我,那太棒了! 因此,这意味着向远程服务实际发送消息不会影响流程实例的执行性能 。 显然,从这里您可以发疯,添加持久队列和所有这些幻想。 最重要的是,脚本始终是从远程服务器获取的。 如果要更新执行的逻辑,只需更改返回的脚本。 这意味着您可以在不影响实际流程的情况下影响运行时的流程执行。

https://github.com/jbarrez/activiti-advanced-scripting/blob/master/src/test/java/org/activiti/test/ExecuteScriptWithJobTest.java有一个单元测试

如果运行此测试,则会看到以下内容。 请注意,我们在测试服务器上将完成脚本托管为名为“ task-complete.js”的静态文件。

Screen-Shot-2013-07-23-at-09.50.362-1024x171

在测试中,您可以看到我们必须专门执行异步作业才能查看测试的输出。

警告

需要注意的是:当流程引擎重新启动时,将从配置文件中重新加载配置。 因此,不添加从上方插入自定义逻辑的过程。 但是,这可以通过使用ProcessEngineLifeCycleListener实现轻松完成,该实现在引擎启动后执行特定类别的流程定义。 例如,如果将所有这些进程的“ config-processes”都设为类别,则可以轻松地在启动时执行它们。

结论

BPMN 2.0流程中的脚本编写是一项非常强大的功能。 它使您可以在几行之内更改整个引擎的流程执行。 当然,以上所有代码都可以使用Java完成。 但是以上示例仅使用标准BPMN 2.0和每次JDK安装中捆绑的javascript引擎。

谢谢阅读。 编码愉快!

参考: Activiti中的高级脚本: JCG合作伙伴 Joram Barrez在“ 小脚走路”博客上的自定义配置注入

翻译自: https://www.javacodegeeks.com/2013/07/advanced-scripting-in-activiti-custom-configuration-injection.html

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐