首页 > 解决方案 > Activiti:使用 activiti:expression 定义可重用的 ScriptTaskListener 脚本

问题描述

我想在某处定义脚本源代码并从 Activiti 5.12 或更高版本中的多个 ScriptTaskListener 重用它。

假设我taskScript在之前的 groovy 脚本任务中定义了一个 processVariable,其中包含 groovy 源代码:

execution.setVariable("taskScript", 
    'def log = org.slf4j.LoggerFactory.getLogger("my.Logger");log.info("works")')

现在我想org.activiti.engine.impl.bpmn.listener.ScriptTaskListener通过将它作为一个来使用该代码activiti:expression

<activiti:taskListener event="complete" class="org.activiti.engine.impl.bpmn.listener.ScriptTaskListener" >
  <activiti:field name="script">
     <activiti:expression><![CDATA[${taskScript}]]></activiti:expression>
  </activiti:field>
  <activiti:field name="language" stringValue="groovy" />
</activiti:taskListener>

我得到以下异常:

javax.script.ScriptException: groovy.lang.MissingMethodException: 
No signature of method: org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.$() 
is applicable for argument types: (Script657$_run_closure1)

${taskScript}在 Activiti 将表达式传递给 ScriptTaskListener 属性之前,似乎没有对表达式进行评估script,而是 groovy 引擎尝试将其${taskScript}作为 groovy 脚本进行评估。

但是,这可以正常工作:

<activiti:taskListener event="complete" class="org.activiti.engine.impl.bpmn.listener.ScriptTaskListener" >
  <activiti:field name="script">
    <activiti:string>
      def log = org.slf4j.LoggerFactory.getLogger("my.Logger");
      log.info("works")
    </activiti:string>
  </activiti:field>
  <activiti:field name="language" stringValue="groovy" />
</activiti:taskListener>

我很困惑为什么我不能这样做。activiti:expression在应用于activiti:field?

是否有不同的方法可以在 ScriptTaskListeners 中重用脚本代码?

标签: groovyactiviti

解决方案


关键是 ScriptTaskListener 如何评估表达式。它不计算 UEL 表达式并将其传递给 Groovy,而是只让 Groovy 引擎计算表达式。我们需要将 groovy 脚本作为表达式而不是${taskScript}UEL 表达式传递。

事实证明这是有效的:

<activiti:expression><![CDATA[
try {
  evaluate(task.getVariable("taskScript"));
} catch (ex) {
  def log = org.slf4j.LoggerFactory.getLogger("my.Logger");
  log.warn("failed to invoke taskScript", ex)
}
]]>
</activiti:expression>

评估调用必须与 try..catch 嵌套,因为侦听器中的异常会阻止事件被处理,因此您的进程将永久停止。


推荐阅读