1. 程式人生 > >activiti(7):監聽器之流程監聽及spring注入

activiti(7):監聽器之流程監聽及spring注入

這篇文章主要記錄流程監聽器的部分用法,整個環境實在整合在spring下,ssm環境:

三個監聽器:

A:普通javaBean:

package com.abc.activiti.listenner;


import org.activiti.engine.delegate.DelegateExecution;


public class JavaExpressionActivitiListenner {


	public void expression(DelegateExecution execution) throws Exception {
		System.out.println("executionId:" + execution.getId() + " ActivitiListenner" + this.toString());
	}
}

B:實現ExecutionListener介面:

package com.abc.activiti.listenner;


import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.TaskListener;


public class ActivitiListenner implements TaskListener, ExecutionListener {


	/**
	 * 
	 */
	private static final long serialVersionUID = -3759054058055401826L;


	@Override
	public void notify(DelegateExecution execution) throws Exception {
		System.out.println("xml流程:" + execution.getId() + " ActivitiListenner" + this.toString());
	}


	@Override
	public void notify(DelegateTask delegateTask) {
		System.out.println("xml任務:" + delegateTask.getId() + " ActivitiListenner" + this.toString());
	}


}

C:實現JavaDelegate介面

package com.abc.activiti.listenner;


import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;


public class JavaDelegateActivitiListenner implements JavaDelegate {


@Override
public void execute(DelegateExecution execution) throws Exception {
System.out.println("executionId:" + execution.getId() + " ActivitiListenner" + this.toString());
}


}


第一種嘗試:javaClass配置實現監聽

流程設計:


流程非常短:啟動-辦理-結束,並配置了三個監聽器

監聽器配置:

<process id="abc" name="流程監聽注入" isExecutable="true">
<extensionElements>
<activiti:executionListener event="start"
class="com.abc.activiti.listenner.xxxListenner"></activiti:executionListener>
<activiti:executionListener event="end"
class="com.abc.activiti.listenner.xxxListenner"></activiti:executionListener>
</extensionElements>
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="User Task"></userTask>
<sequenceFlow id="flow1" sourceRef="startevent1"
targetRef="usertask1"></sequenceFlow>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1">
<extensionElements>
<activiti:executionListener event="take"
class="com.abc.activiti.listenner.xxxListenner"></activiti:executionListener>
</extensionElements>
</sequenceFlow>
</process>

A類監聽測試:

2017-09-16 10:36:25.816 [http-nio-8080-exec-3] ERROR c.a.a.controller.ActivitiController.exception - 處理請求http://localhost:8080/abc-master/activiti/start?null 時出錯。
完整異常棧堆資訊
org.activiti.engine.ActivitiIllegalArgumentException: com.abc.activiti.listenner.JavaExpressionActivitiListenner doesn't implement interface org.activiti.engine.delegate.ExecutionListener nor interface org.activiti.engine.delegate.JavaDelegate
啟動流程時報錯,說明通過javaClass配置activiti的流程監聽器必須實現org.activiti.engine.delegate.ExecutionListener或者org.activiti.engine.delegate.JavaDelegate介面

B類監聽測試:

流程啟動-辦理-結束,三個監聽器的方法分別被執行:執行結果如下:
xml流程:7f7aa2be-9a89-11e7-9d02-b4b6761cb4ac [email protected]ca6dcd
xml流程:7f7aa2be-9a89-11e7-9d02-b4b6761cb4ac [email protected]6a75c6
xml流程:7f7aa2be-9a89-11e7-9d02-b4b6761cb4ac [email protected]2664da
測試表明,通過載入java class的方式去載入實現了ExecutionListener介面的bean,可以順利實現流程監聽,但是每次獲取的監聽器都是一個新物件;

C類監聽測試:

執行結果如下:
executionId:eebefb34-9a89-11e7-b1f2-b4b6761cb4ac ActivitiLi[email protected]26d8afc4
executionId:eebefb34-9a89-11e7-b1f2-b4b6761cb4ac ActivitiLi[email protected]38835b92
executionId:eebefb34-9a89-11e7-b1f2-b4b6761cb4ac ActivitiLi[email protected]21dcaa6e
不出所料,其結果與B類監聽一致;

進一步測試:spring容器注入bean:

可以設想一下,javaClass載入監聽器的時,每次都是activitiEngine通過反射產生新的物件,因此此種方式下通過spring管理去注入可能會失敗: 對實現了JavaDelegate的監聽器進行改造:
package com.abc.activiti.listenner;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.abc.activiti.service.ActivitiService;

@Service
public class JavaDelegateActivitiListenner implements JavaDelegate {

	@Autowired
	private ActivitiService activitiService;

	@Override
	public void execute(DelegateExecution execution) throws Exception {
		System.out.println("executionId:" + execution.getId() + " ActivitiListenner" + this.toString()
				+ "  spring容器注入bean:" + activitiService.toString());
	}

}

測試結果:

妥妥的空指標,注入失敗:
2017-09-16 10:57:01.760 [http-nio-8080-exec-3] ERROR c.a.a.controller.ActivitiController.exception - 處理請求http://localhost:8080/abc-master/activiti/start?null 時出錯。
完整異常棧堆資訊
java.lang.NullPointerException: null
	at com.abc.activiti.listenner.JavaDelegateActivitiListenner.execute(JavaDelegateActivitiListenner.java:19) ~[JavaDelegateActivitiListenner.class:na]
	at org.activiti.engine.impl.delegate.JavaDelegateInvocation.invoke(JavaDelegateInvocation.java:34) ~[activiti-engine-5.20.0.jar:na]
對實現了ExecutionListener的監聽器進行改造:
package com.abc.activiti.listenner;


import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.TaskListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import com.abc.activiti.service.ActivitiService;


@Service
public class ActivitiListenner implements TaskListener, ExecutionListener {


/**
 * 
 */
private static final long serialVersionUID = -3759054058055401826L;


@Autowired
private ActivitiService activitiService;


@Override
public void notify(DelegateExecution execution) throws Exception {
System.out.println("xml流程:" + execution.getId() + " ActivitiListenner" + this.toString());
System.out.println("activitiService: " + activitiService.toString());
}


@Override
public void notify(DelegateTask delegateTask) {
System.out.println("xml任務:" + delegateTask.getId() + " ActivitiListenner" + this.toString());
}


}

測試結果:

xml流程:03ec2a11-9a8b-11e7-903c-b4b6761cb4ac [email protected]e11ac2
2017-09-16 10:59:11.541 [http-nio-8080-exec-3] ERROR c.a.a.controller.ActivitiController.exception - 處理請求http://localhost:8080/abc-master/activiti/start?null 時出錯。
完整異常棧堆資訊
java.lang.NullPointerException: null
at com.abc.activiti.listenner.ActivitiListenner.notify(ActivitiListenner.java:26) ~[ActivitiListenner.class:na]
at org.activiti.engine.impl.delegate.ExecutionListenerInvocation.invoke(ExecutionListenerInvocation.java:34) ~[activiti-engine-5.20.0.jar:na]
以上兩組結果表明,spring只是將其納入管理,但併成功注入到activitiEngine中。

第二種嘗試:expression配置實現監聽

監聽器配置:

<process id="abc" name="流程監聽注入" isExecutable="true">
		<extensionElements>
			<activiti:executionListener event="start"
				expression="${javaExpressionActivitiListenner.expression(execution)}"></activiti:executionListener>
			<activiti:executionListener event="end"
				expression="${javaExpressionActivitiListenner.expression(execution)}"></activiti:executionListener>
		</extensionElements>
		<startEvent id="startevent1" name="Start"></startEvent>
		<userTask id="usertask1" name="User Task"></userTask>
		<sequenceFlow id="flow1" sourceRef="startevent1"
			targetRef="usertask1"></sequenceFlow>
		<endEvent id="endevent1" name="End"></endEvent>
		<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1">
			<extensionElements>
				<activiti:executionListener event="take"
					expression="${javaExpressionActivitiListenner.expression(execution)}"></activiti:executionListener>
			</extensionElements>
		</sequenceFlow>
	</process>

A類監聽測試:

需要注意的是,此時通過expression表示式注入時,是的
2017-09-16 11:27:29.420 [http-nio-8080-exec-3] ERROR c.a.a.controller.ActivitiController.exception - 處理請求http://localhost:8080/abc-master/activiti/start?null 時出錯。
完整異常棧堆資訊
org.activiti.engine.ActivitiException: Unknown property used in expression: ${javaExpressionActivitiListenner.expression(execution)}
	at org.activiti.engine.impl.el.JuelExpression.getValue(JuelExpression.java:53) ~[activiti-engine-5.20.0.jar:na]
......
Caused by: org.activiti.engine.impl.javax.el.PropertyNotFoundException: Cannot resolve identifier 'javaExpressionActivitiListenner'
	at org.activiti.engine.impl.juel.AstIdentifier.eval(AstIdentifier.java:83) ~[activiti-engine-5.20.0.jar:5.20.0]

監聽器改造:

package com.abc.activiti.listenner;

import org.activiti.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;

@Component
public class JavaExpressionActivitiListenner {

	public void expression(DelegateExecution execution) throws Exception {
		System.out.println("executionId:" + execution.getId() + " ActivitiListenner" + this.toString());
	}
}
測試結果如下:
executionId:ddd3f07e-9a8d-11e7-9fc5-b4b6761cb4ac ActivitiList[email protected]420a38c6
executionId:ddd3f07e-9a8d-11e7-9fc5-b4b6761cb4ac ActivitiList[email protected]420a38c6
executionId:ddd3f07e-9a8d-11e7-9fc5-b4b6761cb4ac ActivitiList[email protected]420a38c6

B類監聽測試:

測試結果:

xml流程:2175ef09-9a8e-11e7-9af4-b4b6761cb4ac [email protected]68610c
xml流程:2175ef09-9a8e-11e7-9af4-b4b6761cb4ac [email protected]68610c
xml流程:2175ef09-9a8e-11e7-9af4-b4b6761cb4ac [email protected]68610c

C類監聽測試:

測試結果:

executionId:719dc30a-9a8d-11e7-9ac9-b4b6761cb4ac ActivitiLi[email protected]7374d21e
executionId:719dc30a-9a8d-11e7-9ac9-b4b6761cb4ac ActivitiLi[email protected]7374d21e
executionId:719dc30a-9a8d-11e7-9ac9-b4b6761cb4ac ActivitiLi[email protected]7374d21e

進一步測試:spring注入bean:

測試結果:
xml流程:2b882f40-9a91-11e7-9325-b4b6761cb4ac [email protected]e9857e
activitiService: [email protected]
xml流程:2b882f40-9a91-11e7-9325-b4b6761cb4ac [email protected]e9857e
activitiService: [email protected]
xml流程:2b882f40-9a91-11e7-9325-b4b6761cb4ac [email protected]e9857e
activitiService: [email protected]
此處僅提供A類監聽測試結果,其餘測試結果均一致,以上測試結果表明,使用expression表示式江容器中的bean作為監聽器注入到activitiEngine中是一種非常靈活強大的方式。

第三種嘗試:delegate expression配置實現監聽

監聽器配置:
	<process id="abc" name="流程監聽注入" isExecutable="true">
		<extensionElements>
			<activiti:executionListener event="start"
				delegateExpression="${activitiListenner}"></activiti:executionListener>
			<activiti:executionListener event="end"
				delegateExpression="${activitiListenner}"></activiti:executionListener>
		</extensionElements>
		<startEvent id="startevent1" name="Start"></startEvent>
		<userTask id="usertask1" name="User Task"></userTask>
		<sequenceFlow id="flow1" sourceRef="startevent1"
			targetRef="usertask1"></sequenceFlow>
		<endEvent id="endevent1" name="End"></endEvent>
		<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1">
			<extensionElements>
				<activiti:executionListener event="take"
					delegateExpression="${activitiListenner}"></activiti:executionListener>
			</extensionElements>
		</sequenceFlow>
	</process>
A類監聽測試:
2017-09-16 12:21:54.134 [http-nio-8080-exec-3] ERROR c.a.a.controller.ActivitiController.exception - 處理請求http://localhost:8080/abc-master/activiti/start?null 時出錯。
完整異常棧堆資訊
org.activiti.engine.ActivitiIllegalArgumentException: Delegate expression ${javaExpressionActivitiListenner} did not resolve to an implementation of interface org.activiti.engine.delegate.ExecutionListener nor interface org.activiti.engine.delegate.JavaDelegate
	at org.activiti.engine.impl.bpmn.listener.DelegateExpressionExecutionListener.notify(DelegateExpressionExecutionListener.java:57) ~[activiti-engine-5.20.0.jar:5.20.0]
	at org.activiti.engine.impl.pvm.runtime.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:42) ~[activiti-engine-5.20.0.jar:na]
B類監聽測試:
xml流程:fcc6c8ba-9a95-11e7-826d-b4b6761cb4ac [email protected]425d05
activitiService: [email protected]
xml流程:fcc6c8ba-9a95-11e7-826d-b4b6761cb4ac [email protected]425d05
activitiService: [email protected]
xml流程:fcc6c8ba-9a95-11e7-826d-b4b6761cb4ac [email protected]425d05
activitiService: [email protected]
C類監聽測試:
executionId:c96567e2-9a95-11e7-b7e3-b4b6761cb4ac ActivitiLi[email protected]6f660921  spring容器注入bean:[email protected]
executionId:c96567e2-9a95-11e7-b7e3-b4b6761cb4ac ActivitiLi[email protected]6f660921  spring容器注入bean:[email protected]
executionId:c96567e2-9a95-11e7-b7e3-b4b6761cb4ac ActivitiLi[email protected]6f660921  spring容器注入bean:[email protected]
以上測試結果表明: 通過delegate expression配置容器中的監聽器時,仍然需要實現ExecutionListener或者JavaDelegate介面

總結:

1通過javaClass載入指定類,這種硬編碼的形式管理監聽器,是將class位元組碼檔案交由activitiEngine處理,每次需要的時候則由engine通過反射構建例項物件,spring無法管理; 2通過delegate expression配置容器中的bean作為監聽器,${類名};需要bean自身實現org.activiti.engine.delegate.ExecutionListener或者 org.activiti.engine.delegate.JavaDelegate介面,並重寫對應的方法,在改監聽器被呼叫時,會預設制定重寫方法中的邏輯,此時,bean物件是由spring管理,可以與容器無縫對接; 3通過expression配置容器中的bean作為監聽器,${類名.方法名(引數名)};這是最為靈活也最為強大的方法,可以使用任意的bean,也可以自定義將要執行的方法,與spring容器無縫對接,與業務邏輯完美契合。