如何向TaskListener向iframe注入js脚本

1017人阅读
1.有时候在项目中需要定时启动某个任务,对于这个需求,基于JavaEE规范,我们可以使用Listener与TimerTask来实现,代码如下:
public class TestTaskListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
new TestTimerManager();
public TestTaskListener() {
public void contextDestroyed(ServletContextEvent sce) {
2.contextInitialized方法中新建了一个定时管理器,代码如下:
public class TestTimerManager {
Timer timer = new Timer();
public TestTimerManager() {
TestTimerTask task = new TestTimerTask();
timer.schedule(task, firstTimeToStartTheTask, period);
3.在定时任务的Constructor中新建了一个定时任务,其代码如下:
@Configuration
public class TestTimerTask extends TimerTask {
@Autowired
private SelectDataService selectDataS
public TestTimerTask() {
public void run(){
MyData myData = selectDataService.selectMyDataById(id);
}catch(Exception ex) {
System.out.println("定时任务出错");
ex.printStackTrace();
Spring是个性能非常优秀的抽象工厂,可以生产出工程所需要的实例,这里采用Spring容器的自动注入selectDataService实例。上面代码中,selectDataService这个类是采用Spring的@Service注解的,在项目中主要通过Spring容器注入到Controller中,其作用主要用来访问数据库。
运行项目将会发现NullPointerException,也就是说SelectDataService的实例没有被注入到变量selectDataService中。那么,这是什么原因呢?首先来看看配置文件。
下面是web.xml:
&contextConfigLocation&
&classpath:applicationContext.xml&
&org.springframework.web.context.ContextLoaderListener&
&com.test.TestTaskListener&
在启动web项目时,Servlet容器(比如Tomcat)会读web.xml配置文件中的两个节点和,节点用来加载appliactionContext.xml(即Spring的配置文件),节点用来创建监听器(比如TestTaskListener)实例。Listener的生命周期是由servlet容器管理的,例中的TestTaskListener是由servlet容器实例化并调用其contextInitialized方法的,但是,SelectDataService是通过@Service注解的,也就是说SelectDataService是由Spring容器管理的,在Spring容器外无法直接通过依赖注入得到Spring容器管理的bean实例的引用。为了在Spring容器外得到Spring容器管理的bean,可以使用Spring提供的工具类WebApplicationContextUtils。也就是说,可以在servlet容器管理的Listener中使用该工具类获Spring管理的bean。
看如下代码:
public class TestTaskListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
SelectDataService selectDataService = ctx.getBean(SelectDataService.class);
new TestTimerManager();
public TestTaskListener() {
public void contextDestroyed(ServletContextEvent sce) {
那么在Listener中获得的SelectDataService实例如何在TestTimerTask中使用呢?可以通过作为参数传递过去,看如下代码:
public class TestTaskListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
SelectDataService selectDataService = ctx.getBean(SelectDataService.class);
new TestTimerManager(selectDataService);
public TestTaskListener() {
public void contextDestroyed(ServletContextEvent sce) {
public class TestTimerManager {
Timer timer = new Timer();
public TestTimerManager(SelectDataService selectDataService) {
TestTimerTask task = new TestTimerTask(selectDataService);
timer.schedule(task, firstTimeToStartTheTask, period);
@Configuration
public class TestTimerTask extends TimerTask {
private SelectDataService selectDataS
public TestTimerTask(SelectDataService selectDataService) {
this.selectDataService = selectDataS
public void run(){
MyData myData = selectDataService.selectMyDataById(id);
}catch(Exception ex) {
System.out.println("定时任务出错");
ex.printStackTrace();
再回到web.xml
由于Servlet容器在初始化TestTaskListener时,获取了Spring容器,所以必须保证,在此之前,Spring容器已经初始化完成。因为Spring容器的初始化也是由Listener(ContextLoaderListener)完成,该监听器用Spring框架提供,可以在web应用启动时启动Spring容器。所以,在web.xml中,要先配置ContextLoaderListener,再配置TestTaskListener。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2337次
排名:千里之外
(1)(1)(3)(2)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'activiti监听器使用
activiti使用的时候,通常需要跟业务紧密的结合在一起,有些业务非常的复杂,通常有如下一些场景:
1.activiti人员动态的分配。
2.当前任务节点完成的时候,指定需要指定下一个节点的处理人(比如,一个请假流程,a员工请假,需要指定下一步需要处理请假流程的领导。)。
3.任务节点完成的时候,需要一些复杂业务,(比如当前节点完成的时候,需要调用我们的jms消息发送消息)。
4.任务流转到当前的节点的时候,需要监控当前任务节点的一些信息或者其他的业务信息。
5.当前的任务节点分配处理人的时候,需要触发自定义的一些业务。
6.流程开始结束的时候,需要处理业务信息。
7.经过任务节点的出线,也就是连线的时候,需要触发自定义的业务。
那我们怎么实现以上的这些需求呢?这个时候,我们就需要使用activiti监听器,activiti提供的监听器怎么实现,以及如何触发,这些都需要我们一步步了解。下面就详细的介绍activiti监听器。
从activiti监听器的使用范围来看,大致分为三种:
1.全局的监听器。
2.连线的监听器。
3.节点的监听器。
下面我们一个个的来看如何使用这些监听器。
1.1.1.全局的监听器
全局监听器主要使用的场景就是监控这个流程的启动和结束。流程开始的时候可以监控,流程结束的时候可以监控,这里说的是流程实例启动结束的监控,并非是流程引擎的启动结束监控。流程引擎的启动结束监控可以参考https://blog.csdn.net/qq_/article/details/ 不要混淆了这些概念。
下面我们先定义一个简单的bpmn xml文件看一下如何使用全局的监听器。
全局监听器实现的接口是org.activiti.engine.delegate.ExecutionListener,org.activiti.engine.impl.pvm.delegate.ExecutionListener这个接口新版本已经废弃。
1.1.1.1.ExecutionListener定义
ExecutionListener定义如下:流程实例start、end、take的时候调用。take是监控连线的时候使用的。
public interface ExecutionListener extends Serializable {
String EVENTNAME_START = &start&;
String EVENTNAME_END = &end&;
String EVENTNAME_TAKE = &take&;
void notify(DelegateExecution execution) throws E
下面定义一个类监控流程实例的启动监控,看如何使用。
1.1.1.2.流程图
1.1.1.3.流程定义xml
流程的xml如下所示:
1.1.1.4.监听类
上面我们定义了两个监听器分别指向同一个类com.daling.ch1.listener.MyExecutionListener我们在类中监控事件。
com.daling.ch1.listener.MyExecutionListener类的实现如下所示:
package com.daling.ch1.
import org.activiti.engine.delegate.DelegateE
import org.activiti.engine.delegate.ExecutionL
public class MyExecutionListener implements ExecutionListener {
public void notify(DelegateExecution execution) throws Exception {
String eventName = execution.getEventName();
if (&start&.equals(eventName)) {
System.out.println(&start=========&);
}else if (&end&.equals(eventName)) {
System.out.println(&end=========&);
1.1.1.5.开始监控
下面我们部署启动流程看一下效果,部署流程可参考之前的章节,启动流程如下所示:
ProcessInstance processInstance= runtimeService
.startProcessInstanceByKey(key,vars);
我们看一下程序的部分输出如下:
08:34:07.050 [main] DEBUG o.a.e.i.h.DefaultHistoryManager - Current history level: AUDIT, level required: ACTIVITY
08:34:07.056 [main] DEBUG o.a.e.i.h.DefaultHistoryManager - Current history level: AUDIT, level required: ACTIVITY
08:34:07.057 [main] DEBUG o.a.e.i.h.DefaultHistoryManager - Current history level: AUDIT, level required: FULL
start=========
08:34:07.064 [main] DEBUG o.a.e.i.p.r.AtomicOperationActivityExecute - ProcessInstance[107509] executes Activity(startevent1): org.activiti.engine.impl.bpmn.behavior.NoneStartEventActivityBehavior
08:34:07.064 [main] DEBUG o.a.e.i.p.e.J.selectJobsByExecutionId - ooo Using Connection [com..jdbc.JDBC4Connection@eeb514]
08:34:07.064 [main] DEBUG o.a.e.i.p.e.J.selectJobsByExecutionId - ==& Preparing: select * from ACT_RU_JOB J where J.EXECUTION_ID_ = ?
可以看出流程实例启动的时候,触发了我们自定义的类中的函数。
1.1.1.6.结束监控
下面我们把usertask的任务结束,然后流程实例结束,看看触发了我们自定义的类中的end没有。
String taskId=&107515&;
demo.getTaskService().complete(taskId);
我们看一下程序的部分输出如下:
08:39:22.016 [main] DEBUG o.a.e.i.p.r.AtomicOperationActivityExecute - ProcessInstance[107509] executes Activity(endevent1): org.activiti.engine.impl.bpmn.behavior.NoneEndEventActivityBehavior
08:39:22.016 [main] DEBUG o.a.e.i.h.DefaultHistoryManager - Current history level: AUDIT, level required: ACTIVITY
end=========
1.1.1.7.DelegateExecution类
在上面的全局监听器中我们可以拿到DelegateExecution对象,这个对象可以让我们操作activiti引擎中的一些东西,下面看一下DelegateExecution类中的定义。
DelegateExecution类图如下:
启动最常用的方法如下:
/** execution Id */
String getId();
流程实例id*/
String getProcessInstanceId();
/** 这个比较有用 主要就是start、end、take
String getEventName();
业务id已经废弃
String getBusinessKey();
String getProcessBusinessKey();
* 流程定义id
String getProcessDefinitionId();
* 获取父id,并发的时候有用
String getParentId();
* 获取当前的.Activityid
String getCurrentActivityId();
* 获取当前的.Activity name
String getCurrentActivityName();
* 获取TenantId 当有多个TenantId 有用
String getTenantId();
* 这个非常有用吧。当拿到EngineServices 对象所有的xxxService都可以拿到。
EngineServices getEngineServices();
1.1.2.连线监听器
当节点结束的时候,经过连线的时候,我们可以在线上定义类,实现自己的业务逻辑。连线监听器怎么实现呢?
这里为了方便测试,我们还是采用上面全局监听器中的流程图,下面我们自定义一个连线监听器类,看看如何使用,可以拿到什么对象。
1.1.2.1.流程图
1.1.2.2.流程定义xml
1.1.2.3.监听类
上面我们定义了一个监听器com.daling.ch1.listener.MyExecutionListener类中监控事件。
public class MyExecutionListener implements ExecutionListener {
private static final long serialVersionUID = 9642910L;
//ExecutionListener类的实现
public void notify(DelegateExecution execution) throws Exception {
String eventName = execution.getEventName();
if (&start&.equals(eventName)) {
System.out.println(&start=========&);
}else if (&end&.equals(eventName)) {
System.out.println(&end=========&);
else if (&take&.equals(eventName)) {
System.out.println(&take=========&);
因为我们在flow3中定义的监听类,所以流程经过flow3的时候触发定义的take中的自定义事件。
1.1.3.节点监听器
1.1.3.1.节点监听器定义
在实际项目开发中,任务节点是经常用到的,所以我们必须要会使用节点监听器。
节点监听器的定义接口org.activiti.engine.delegate.TaskListener,org.activiti.engine.impl.pvm.delegate.TaskListener已经废弃不用。
TaskListener类的定义如下所示:
String EVENTNAME_CREATE = &create&;
String EVENTNAME_ASSIGNMENT = &assignment&;
String EVENTNAME_COMPLETE = &complete&;
String EVENTNAME_DELETE = &delete&;
* Not an actual event, used as a marker-value for {@link TaskListener}s that should be called for all events,
* including {@link #EVENTNAME_CREATE}, {@link #EVENTNAME_ASSIGNMENT} and {@link #EVENTNAME_COMPLETE} and {@link #EVENTNAME_DELETE}.
String EVENTNAME_ALL_EVENTS = &all&;
void notify(DelegateTask delegateTask);
1.1.3.2.节点监听器类图
节点监听器的子类如下图所示:
下面开始我们详细的使用吧。首先还是定义一个xml,xml流程还是上面所示的,只是多了一些任务节点的监听。
1.1.3.3.流程图
1.1.3.4.流程定义xml
流程的xml如下所示:
1.1.3.5.监听类
任务节点的监听只要实现TaskListener接口即可。下面是任务监听的实现类,如下所示:
public class MyExecutionListener implements ExecutionListener,TaskListener {
private static final long serialVersionUID = 9642910L;
//ExecutionListener类的实现
public void notify(DelegateExecution execution) throws Exception {
String eventName = execution.getEventName();
if (&start&.equals(eventName)) {
System.out.println(&start=========&);
}else if (&end&.equals(eventName)) {
System.out.println(&end=========&);
else if (&take&.equals(eventName)) {
System.out.println(&take=========&);
//实现TaskListener中的方法
public void notify(DelegateTask delegateTask) {
String eventName = delegateTask.getEventName();
if (&create&.endsWith(eventName)) {
System.out.println(&create=========&);
}else if (&assignment&.endsWith(eventName)) {
System.out.println(&assignment========&);
}else if (&complete&.endsWith(eventName)) {
System.out.println(&complete===========&);
}else if (&delete&.endsWith(eventName)) {
System.out.println(&delete=============&);
当流程运转到usertask2我们看一下程序的输出:
assignment========
create=========
因为usertask2节点配置了处理人所以触发assignment事件监听,当任务运转到usertask2的时候触发了create事件。
这里我们也可以得出一个结论:assignment事件比create先执行。
使用代码结束任务,代码如下:
String taskId=&127515&;
demo.getTaskService().complete(taskId);
当我们结束usertask2我们看一下程序的输出:
complete===========
delete=============
在这里我们可以得出结论:
任务完成的时候,触发complete事件,因为任务完成之后,要从ACT_RU_TASK中删除这条记录,所以触发delete事件。
1.1.3.6.DelegateTask类
在上面的任务监听器中我们可以拿到DelegateTask对象,这个对象可以让我们操作activiti引擎中的一些东西,下面看一下DelegateTask类中的定义主要访法。
public interface DelegateTask extends VariableScope {
/** 中的taskId主键*/
String getId();
/** 任务名称 */
String getName();
/** 修改任务名称 */
void setName(String name);
/** 获取任务的描述信息 */
String getDescription();
/** 修改任务的描述信息 */
void setDescription(String description);
* lower priority: [0..19] lowest, [20..39] low, [40..59] normal, [60..79] high
* [80..100] highest
任务处理的优先级范围是0-100
int getPriority();
/** 修改优先级*/
void setPriority(int priority);
/** 获取流程实例id */
String getProcessInstanceId();
/**获取执行id*/
String getExecutionId();
/** 获取流程定义id*/
String getProcessDefinitionId();
/** Adds the given user as a candidate user to this task. */
void addCandidateUser(String userId);
/** 添加候选人 */
void addCandidateUsers(Collection candidateUsers);
/** 添加候选组 */
void addCandidateGroup(String groupId);
上面我们总结了,全局监听器、连线、任务节点的使用,下面我们看一下共性的东西再做一次总结。
1.1.4.其他的使用方式
1.1.4.1.spring整合
上面我们在定义类的的时候,我们直接使用的类定义的方式,当然我们还可以跟sring整合使用,因为在实际项目中类的管理可能交给spring容器。使用也很简单如下图所示:
需要填写的表达书,只需要使用spring方式注入即可,${}里面的值为需要使用的bean在spring中的id.可以xml定义或者在注解中定义。注解中定义需要开启spring包扫描机制。比如我的@Service(&myExecutionListener&)。
1.1.5.小结
1.activiti监听方式分为三大类,节点监听、全局监听、连线监听。
2.activiti监听主要实现的类是两个 节点监听、全局监听实现org.activiti.engine.delegate.ExecutionListener
节点的监听实现org.activiti.engine.delegate.TaskListener接口即可。
3.监听器其实就是一个观察者模式。(关于观察者模式,我们后续章节讲解,限于篇幅有限)
4.监听器获取spring对象,如何获取spring中的bean呢?
1.1.6.遗留点
5.监听器关于观察者模式,我们后续章节讲解。
6.监听器获取spring对象,如何获取spring中的bean呢?留到下一个章节讲解吧。pleteTask(task.getId());
单步跟踪下去的顺序
1、执行函数体内,得到dbid,感觉是注入到这个id去的。在taskimpl中有setdbid的方法
2、commandService.execute(new CompleteTaskCmd(taskId));
3、在CompleteTaskCmd中,public Void execute(Environment environment) throws Exception
{
//要从数据库中取数据,因为task是在进入节点的时候,产生到数据库中的
&& TaskImpl task = dbSession.get(TaskImpl.class, Long.parseLong(taskId));
&&& if (outcomeSpecified) {
&&&&& plete(outcome);
&&& } else {
&&&&& plete();&
在Complete中
//它在历史事件中Update了historytask,主要是更新了endtime及setTransitionName
&&&
historyTaskComplete(outcome);
//在historyEvent 基类下,有taskCreate等多个子类,每个子类,都采用模板的Process的方式。说明任务在创建到结束的时候,该事件都会被启动
&&&
&&& DbSession dbSession = EnvironmentImpl.getFromCurrent(DbSession.class, false);
&&& if (dbSession!=null){
&&&&& dbSession.delete(this);//应该是删除task本身的任务
&&& }
&&& if (isSignalling()) {
&&&&& ClientExecution execution = getExecution();
&&&&& execution.signal(outcome);
//进入了ExecutionImpl的signal的方法
public void signal(String signal, Map&String, ?& parameters) {
&&& checkActive();
&&& if (getProcessDefinition().isSuspended()) {
&&&&& throw new JbpmException("process definition "+getProcessDefinition().getId()+" is suspended");
&&& }
&&& propagation = Propagation.EXPLICIT;
&&& if (getActivity()!=null) {
&&&&& performAtomicOperation(new Signal(signal, parameters));
//signal也是AtomicOperation子类,但是这个时候,无法通过字符串常量方式写入。
在这里面,主要执行了
activityBehaviour.signal(execution, signalName, parameters);
进入了taskActivity(是activityBehaviour的子类)的signal中。
execution.fire(signalName, activity);在这个fire中,产生了事件的原子操作
&&& AtomicOperation.EXECUTE_EVENT_LISTENER。
然后进入了 public void take(Transition transition) {
fire(Event.END, getActivity(), AtomicOperation.TRANSITION_END_ACTIVITY);
然后执行 TransitionTake
然后执行 TRANSITION_START_ACTIVITY
感觉在 while (! atomicOperations.isEmpty()) {
&&&&&&&&& AtomicOperation atomicOperation = atomicOperations.poll();
&&&&&&&&& atomicOperation.perform(this);
&&&&&&& }
处使用了递归的过程
&&& }
&&& else if (transition != null) {
&&&&& performAtomicOperation(AtomicOperation.TRANSITION_START_ACTIVITY);
&&& }
&&& else {
&&&&& throw new JbpmException("execution is not in a activity or in a transition");
&&& }
& }
//
&&& }
&&&
&&& if (superTask != null) {
&&&&& superTask.subTaskComplete(this, outcome);
&&& }
感觉:在Atomic几个子类操作的互转过程,与信号量的Perti网理论上,应该可以是类似的
浏览: 28245 次
来自: 南京
同文章结合《面向对象的思考过程(原书第2版)》是本不错的书,同 ...
面向对象设计者 在设计的时候,不仅仅关注整个过程化的内容。还要 ...
顶,对面向对象面向过程的困惑又少了一点}

我要回帖

更多关于 向单例注入服务 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信