Quartz中扩展MethodInvokingJobDetailFactoryBean实现对任务调度的拦截
2013-10-09 14:07
706 查看
利用Quartz来实现对任务的调度已经被广泛地应用了,一个利用Quartz来进行任务调度的典型配置如下:
[java] view plaincopy
<bean id="testTask" class="com.alisoft.xx.TestTask" />
<bean id="xxJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="concurrent">
<value>false</value>
</property>
<property name="targetObject">
<ref bean="testTask"/>
</property>
<property name="targetMethod">
<value>execute</value>
</property>
</bean>
<!-- SimpleTriggerBean可以用org.springframework.scheduling.quartz.CronTriggerBean代替 -->
<bean id="xxTriggerBean" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail">
<ref bean="xxJobDetail"/>
</property>
<property name="startDelay">
<value>1000</value>
</property>
<property name="repeatInterval">
<value>60000</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="xxTriggerBean"/>
</list>
</property>
</bean>
若有多个任务需要调度,则配置多个JobDetail、Trigger即可,待执行的Task bean没有啥任何要求,不需要extends任何class、或者implements任何interface,只是被执行的method需要是无参数的;
但是在我们现实项目中,仅仅完成这样的功能是还不够的,我们还需要争取完成以下几点:
对所有的Task实现执行开始、结束时间的记录;
对每天的Task执行结果持久化、或者通过email、旺旺消息等方式告知相关owner;
当我们有多台Task服务器时,如何保证每个任务只在一台服务器上执行;
针对以上几个问题,我们也都有很简单、直接的办法可以搞定,比如说1、2两点可以直接在每个任务中各自编码完成,但是这样不仅每个task都要写非常类似的重复代码、而且不能保证每个任务的执行情况都被记录,因为某些task的编码人员就不会在意这些非功能性需求;对于第3点,我们也可以通过配置来完成向不同task服务器部署不一样的发布包来完成,但这给发布带来了麻烦,这意味着有多少台task服务器,就需要通过修改配置重新打包并发布多少次;
其实我们可以利用Spring默认提供的AOP来非常优雅的解决这几个问题:扩展MethodInvokingJobDetailFactoryBean来实现对任务调度时的拦截!其关键代码为MethodInvokingJobDetailFactoryBean.MethodInvokingJob.executeInternal(JobExecutionContext context);这个method中;
具体步骤如下:
新增所有Task都需要实现的interface,可参考如下代码:
[java] view plaincopy
public interface TaskHandler {
/**
* 任务调度执行需要实现的method
*/
TaskResult execute();
}
基于MethodInvokingJobDetailFactoryBean实现自定义的JobDetailFactoryBean,在具体执行待调度任务的method前后加入公用逻辑,比如记录开始、结束日期、判断该task是否由该台服务器执行、任务执行完成之后将运行结果进行持久化或者发email等给相关owner;可参考如下代码:
[java] view plaincopy
public class AppsMethodInvokingJobDetailFactoryBean extends
MethodInvokingJobDetailFactoryBean {
protected static final Log logger = LogFactory.getLog(AppsMethodInvokingJobDetailFactoryBean.class);
/* (non-Javadoc)
* @see org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws ClassNotFoundException,
NoSuchMethodException {
super.afterPropertiesSet();
logger.info("origin jobClass : " + ((JobDetail)super.getObject()).getJobClass().getName());
// Consider the concurrent flag to choose between stateful and stateless job.
if(MethodInvokingJob.class.getName().equals(((JobDetail)super.getObject()).getJobClass().getName())) {
((JobDetail)super.getObject()).setJobClass(AppsMethodInvokingJob.class);
} else {
((JobDetail)super.getObject()).setJobClass(AppsStatefulMethodInvokingJob.class);
}
logger.info("new jobClass : " + ((JobDetail)super.getObject()).getJobClass().getName());
}
public static class AppsMethodInvokingJob extends MethodInvokingJob {
protected static final Log logger = LogFactory.getLog(AppsMethodInvokingJob.class);
private MethodInvoker methodInvoker;
private String errorMessage;
/**
* Set the MethodInvoker to use.
*/
public void setMethodInvoker(MethodInvoker methodInvoker) {
this.methodInvoker = methodInvoker;
this.errorMessage = "Could not invoke method '" + this.methodInvoker.getTargetMethod() +
"' on target object [" + this.methodInvoker.getTargetObject() + "]";
}
/**
* Invoke the method via the MethodInvoker.
*/
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
Date startDate = new Date();
String taskName = methodInvoker.getTargetClass().getName();
TaskResult taskResult;
try {
if (logger.isInfoEnabled()) {
logger.info(taskName + " job start at " + startDate);
}
//根据当前服务器主机名或者IP判断是否需要执行该任务
//TODO Code
//调用具体task执行method代码
taskResult = this.methodInvoker.invoke();
} catch (Exception ex) {
logger.error(taskName + " accounted a error : " + this.errorMessage, ex);
throw new JobExecutionException(this.errorMessage, ex, false);
} finally {
if(logger.isInfoEnabled()) {
logger.info(taskName + " job end at " + new Date());
}
//将task执行结果taskResult进行持久化、或者通知相关owner
//TODO Code
}
}
}
public static class AppsStatefulMethodInvokingJob extends AppsMethodInvokingJob {
}
}
将自定义JobDetailFactoryBean的bean配置设置为abstract,从而减少每个task的相关配置量,新的代码可参考如下配置:
[java] view plaincopy
<bean id="appsAbstractJobDetail" class="com.alisoft...AppsMethodInvokingJobDetailFactoryBean"
abstract="true">
<property name="concurrent" value="false" />
<property name="targetMethod" value="execute" />
</bean>
<bean id="testTaskHandler" class="com.alisoft...task.TestTaskHandler" />
<bean id="testTaskJobDetail" parent="appsAbstractJobDetail">
<property name="targetObject" ref="testTaskHandler" />
</bean>
<bean id="testTaskTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="testTaskJobDetail" />
<property name="cronExpression" value="0 10 0 * * ?" />
</bean>
原文链接:http://blog.csdn.net/sfdev/article/details/3969673
[java] view plaincopy
<bean id="testTask" class="com.alisoft.xx.TestTask" />
<bean id="xxJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="concurrent">
<value>false</value>
</property>
<property name="targetObject">
<ref bean="testTask"/>
</property>
<property name="targetMethod">
<value>execute</value>
</property>
</bean>
<!-- SimpleTriggerBean可以用org.springframework.scheduling.quartz.CronTriggerBean代替 -->
<bean id="xxTriggerBean" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail">
<ref bean="xxJobDetail"/>
</property>
<property name="startDelay">
<value>1000</value>
</property>
<property name="repeatInterval">
<value>60000</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="xxTriggerBean"/>
</list>
</property>
</bean>
若有多个任务需要调度,则配置多个JobDetail、Trigger即可,待执行的Task bean没有啥任何要求,不需要extends任何class、或者implements任何interface,只是被执行的method需要是无参数的;
但是在我们现实项目中,仅仅完成这样的功能是还不够的,我们还需要争取完成以下几点:
对所有的Task实现执行开始、结束时间的记录;
对每天的Task执行结果持久化、或者通过email、旺旺消息等方式告知相关owner;
当我们有多台Task服务器时,如何保证每个任务只在一台服务器上执行;
针对以上几个问题,我们也都有很简单、直接的办法可以搞定,比如说1、2两点可以直接在每个任务中各自编码完成,但是这样不仅每个task都要写非常类似的重复代码、而且不能保证每个任务的执行情况都被记录,因为某些task的编码人员就不会在意这些非功能性需求;对于第3点,我们也可以通过配置来完成向不同task服务器部署不一样的发布包来完成,但这给发布带来了麻烦,这意味着有多少台task服务器,就需要通过修改配置重新打包并发布多少次;
其实我们可以利用Spring默认提供的AOP来非常优雅的解决这几个问题:扩展MethodInvokingJobDetailFactoryBean来实现对任务调度时的拦截!其关键代码为MethodInvokingJobDetailFactoryBean.MethodInvokingJob.executeInternal(JobExecutionContext context);这个method中;
具体步骤如下:
新增所有Task都需要实现的interface,可参考如下代码:
[java] view plaincopy
public interface TaskHandler {
/**
* 任务调度执行需要实现的method
*/
TaskResult execute();
}
基于MethodInvokingJobDetailFactoryBean实现自定义的JobDetailFactoryBean,在具体执行待调度任务的method前后加入公用逻辑,比如记录开始、结束日期、判断该task是否由该台服务器执行、任务执行完成之后将运行结果进行持久化或者发email等给相关owner;可参考如下代码:
[java] view plaincopy
public class AppsMethodInvokingJobDetailFactoryBean extends
MethodInvokingJobDetailFactoryBean {
protected static final Log logger = LogFactory.getLog(AppsMethodInvokingJobDetailFactoryBean.class);
/* (non-Javadoc)
* @see org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws ClassNotFoundException,
NoSuchMethodException {
super.afterPropertiesSet();
logger.info("origin jobClass : " + ((JobDetail)super.getObject()).getJobClass().getName());
// Consider the concurrent flag to choose between stateful and stateless job.
if(MethodInvokingJob.class.getName().equals(((JobDetail)super.getObject()).getJobClass().getName())) {
((JobDetail)super.getObject()).setJobClass(AppsMethodInvokingJob.class);
} else {
((JobDetail)super.getObject()).setJobClass(AppsStatefulMethodInvokingJob.class);
}
logger.info("new jobClass : " + ((JobDetail)super.getObject()).getJobClass().getName());
}
public static class AppsMethodInvokingJob extends MethodInvokingJob {
protected static final Log logger = LogFactory.getLog(AppsMethodInvokingJob.class);
private MethodInvoker methodInvoker;
private String errorMessage;
/**
* Set the MethodInvoker to use.
*/
public void setMethodInvoker(MethodInvoker methodInvoker) {
this.methodInvoker = methodInvoker;
this.errorMessage = "Could not invoke method '" + this.methodInvoker.getTargetMethod() +
"' on target object [" + this.methodInvoker.getTargetObject() + "]";
}
/**
* Invoke the method via the MethodInvoker.
*/
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
Date startDate = new Date();
String taskName = methodInvoker.getTargetClass().getName();
TaskResult taskResult;
try {
if (logger.isInfoEnabled()) {
logger.info(taskName + " job start at " + startDate);
}
//根据当前服务器主机名或者IP判断是否需要执行该任务
//TODO Code
//调用具体task执行method代码
taskResult = this.methodInvoker.invoke();
} catch (Exception ex) {
logger.error(taskName + " accounted a error : " + this.errorMessage, ex);
throw new JobExecutionException(this.errorMessage, ex, false);
} finally {
if(logger.isInfoEnabled()) {
logger.info(taskName + " job end at " + new Date());
}
//将task执行结果taskResult进行持久化、或者通知相关owner
//TODO Code
}
}
}
public static class AppsStatefulMethodInvokingJob extends AppsMethodInvokingJob {
}
}
将自定义JobDetailFactoryBean的bean配置设置为abstract,从而减少每个task的相关配置量,新的代码可参考如下配置:
[java] view plaincopy
<bean id="appsAbstractJobDetail" class="com.alisoft...AppsMethodInvokingJobDetailFactoryBean"
abstract="true">
<property name="concurrent" value="false" />
<property name="targetMethod" value="execute" />
</bean>
<bean id="testTaskHandler" class="com.alisoft...task.TestTaskHandler" />
<bean id="testTaskJobDetail" parent="appsAbstractJobDetail">
<property name="targetObject" ref="testTaskHandler" />
</bean>
<bean id="testTaskTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="testTaskJobDetail" />
<property name="cronExpression" value="0 10 0 * * ?" />
</bean>
原文链接:http://blog.csdn.net/sfdev/article/details/3969673
相关文章推荐
- Quartz中扩展MethodInvokingJobDetailFactoryBean实现对任务调度的拦截
- Quartz中扩展MethodInvokingJobDetailFactoryBean实现对任务调度的拦截
- Spring整合quartz配置【一】基于MethodInvokingJobDetailFactoryBean实现任务管理
- Quartz-Spring[一]之MethodInvokingJobDetailFactoryBean配置任务
- Quartz-Spring[一]之MethodInvokingJobDetailFactoryBean配置任务
- Quartz+Spring实例应用【一】基于Spring的MethodInvokingJobDetailFactoryBean实现
- Spring 整合Quartz两种方式比较(JobDetailBean和MethodInvokingJobDetailFactoryBean方式)
- Spring里MethodInvokingJobDetailFactoryBean定时任务的小示例
- spring+quartz定时任务配置---MethodInvokingJobDetailFactoryBean
- Quartz学习--Spring整合Quartz(MethodInvokingJobDetailFactoryBean方式)
- Quartz-Spring[一]之MethodInvokingJobDetailFactoryBean方法
- Spring 整合Quartz两种方式(JobDetailBean和MethodInvokingJobDetailFactoryBean方式)
- 使用Spring提供的 MethodInvokingJobDetailFactoryBean 代理类调度定时器
- Spring中使用Quartz的2种方法(extends QuartzJobBean与使用MethodInvokingJobDetailFactoryBean)
- 定时器quartz结合spring使用(方法二MethodInvokingJobDetailFactoryBean)
- Spring整合Quartz(MethodInvokingJobDetailFactoryBean方式)
- Quartz学习(七)--Spring整合Quartz(MethodInvokingJobDetailFactoryBean方式)
- MethodInvokingJobDetailFactoryBean的并发问题
- web 项目 任务调度 Spring整合Quartz(JobDetailBean方式)
- MethodInvokingJobDetailFactoryBean的并发问题