Jboss application server下定制Quartz计划任务

前端时间做过一个关于电子商城的限时抢购活动的功能,当时记得在处理定时业务只是针对于Quartz1.6.5本身的扩展,换句话说Quartz的服务都是部署在web项目中的,这样有个缺点:当你在有很多项目,并且这些项目之间都依赖关系的时候,Quartz服务不能得到重用。

研究了一下Jboss的JMX关于对Quartz的注册,解决了这个难题。

 

首先看一下Quartz服务是如何注册到Jboss上的,另外本人比较推荐使用Jboss4.2.3GA这个版本,之后的版本在发布与spring2.5集成的Web项目时会出现一些问题。

首先,注意一下jboss.4.2.3GA版本中提供的quartz是1.5.0的版本,建议你最好更换。方法如下:

1.quartz-jboss-1.6.5.jar(有兴趣可以看一下这个jar的原代码,这里就是利用JMX去注册到JBOSS服务上的)

2.quartz-1.6.5.jar

将以上两个jar放到{JBOSS_HOME}/{JBOSS_SERVER}/default/lib目录下

现在先看一下quartz-service.xml文件,你可以在{JBOSS_HOME}/{JBOSS_SERVER}/default/deploy这个目录下找到它,打开以后如下:

 

<?xml version="1.0" encoding="UTF-8"?>

 <server>
       <mbeancode="org.quartz.ee.jmx.jboss.QuartzService"name="user:service=QuartzService,name=QuartzService">
           <depends>jboss.jca:service=DataSourceBinding,name=jdbc/StoresgateDS</depends>
            <depends>jboss.jca:service=DataSourceBinding,name=jdbc/StoresgateDS</depends>
            <attribute name="JndiName">Quartz</attribute>
            <attribute name="StartScheduler">true</attribute>
            <attribute name="Properties">
                org.quartz.scheduler.instanceName = DefaultQuartzScheduler
                org.quartz.scheduler.rmi.export = false
                org.quartz.scheduler.rmi.proxy = false
                org.quartz.scheduler.xaTransacted = false
               
                org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
                org.quartz.threadPool.threadCount = 5
                org.quartz.threadPool.threadPriority = 4
               
                org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT
                org.quartz.jobStore.driverDelegateClass =  org.quartz.impl.jdbcjobstore.StdJDBCDelegate
                org.quartz.dataSource.QUARTZ.jndiURL = jdbc/StoresgateDS
                org.quartz.dataSource.QUARTZ_NO_TX.jndiURL = jdbc/StoresgateDS
                org.quartz.jobStore.dataSource = QUARTZ
                org.quartz.jobStore.nonManagedTXDataSource = QUARTZ_NO_TX
                org.quartz.jobStore.tablePrefix = QRTZ_
            </attribute>
   </mbean>
    </server>   

这个配置我不去详细介绍了,有几个关键的配置我大概说一下,也是问题经常会出现的地方。

1.  <depends>jboss.jca:service=DataSourceBinding,name=jdbc/StoresgateDS</depends>

请注意:这里的 jdbc/storesgateDS一定是在JBOSS下的实际数据源的JNDI名称,如果不存在启动服务的时候会抛出异常。

2.   org.quartz.scheduler.rmi.export = false
      org.quartz.scheduler.rmi.proxy = false
      org.quartz.scheduler.xaTransacted = false

这里请注意,如果你希望你的quartz服务可以支持RMI的远程服务,那么这里可以设置成true,否则为false

3. org.quartz.dataSource.QUARTZ.jndiURL = jdbc/StoresgateDS
    org.quartz.dataSource.QUARTZ_NO_TX.jndiURL = jdbc/StoresgateDS

请注意这里的数据源的名字也是一个实际存在的数据源的JNDI名称

 

Schedule schedule = ctx.lookup("Quartz");

这个"Quartz"的定义来源前文的配置文件里的<attribute name="JndiName">Quartz</attribute>
这是一般的做法,但是在EJB环境中,我们是如何来获得quartz的引用并且如何去定义接口呢,请看下面的接口和实现类

 

ScheduleServiceImpl .java

package com.winmess.storesgate.schedule;

/**
 * @author xuxm E-mail:
xuxm@winmess.com
 * @version 创建时间:2009-12-9下午01:13:00
 */

import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

import javax.annotation.PostConstruct;
import javax.ejb.Local;
import javax.ejb.Stateless;

import org.quartz.CronExpression;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.JobDetailBean;
@Stateless
@Local(ScheduleService.class)
public class ScheduleServiceImpl implements ScheduleService {

 private Scheduler scheduler;

 @SuppressWarnings("unused")
 @PostConstruct
 private void initScheduler() {
  try {
   this.scheduler = StdSchedulerFactory.getDefaultScheduler();
   System.out.println("***The schedule init by ScheduleServiceImpl.class**");
  } catch (SchedulerException e) {
   e.printStackTrace();
  }
 }

 @Override
 public void schedule(JobDetail jobDetail, String cronExpression) {
  try {
   schedule(jobDetail, new CronExpression(cronExpression));
  } catch (ParseException e) {
   throw new RuntimeException(e);
  }
 }

 @Override
 public void schedule(JobDetail jobDetail, String name,
   String cronExpression) {
  try {
   schedule(jobDetail, name, new CronExpression(cronExpression));
  } catch (ParseException e) {
   throw new RuntimeException(e);
  }
 }

 @Override
 public void schedule(JobDetail jobDetail, CronExpression cronExpression) {
  schedule(null, cronExpression);
 }

 @Override
 public void schedule(JobDetail jobDetail, String name,
   CronExpression cronExpression) {
  if (name == null || name.trim().equals("")) {
   name = UUID.randomUUID().toString();
  }

  try {
   scheduler.addJob(jobDetail, true);

   CronTrigger cronTrigger = new CronTrigger(name,
     Scheduler.DEFAULT_GROUP, jobDetail.getName(),
     Scheduler.DEFAULT_GROUP);
   cronTrigger.setCronExpression(cronExpression);
   scheduler.scheduleJob(cronTrigger);
   scheduler.rescheduleJob(name, Scheduler.DEFAULT_GROUP,
     cronTrigger);
  } catch (SchedulerException e) {
   throw new RuntimeException(e);
  }
 }

 @Override
 public void schedule(JobDetail jobDetail, Date startTime) {
  schedule(jobDetail, startTime, null);
 }

 @Override
 public void schedule(JobDetail jobDetail, String name, Date startTime) {
  schedule(jobDetail, startTime, null);
 }

 @Override
 public void schedule(JobDetail jobDetail, Date startTime, Date endTime) {
  schedule(jobDetail, startTime, endTime, 0);
 }

 @Override
 public void schedule(JobDetail jobDetail, String name, Date startTime,
   Date endTime) {
  schedule(jobDetail, startTime, endTime, 0);
 }

 @Override
 public void schedule(JobDetail jobDetail, Date startTime, Date endTime,
   int repeatCount) {
  schedule(jobDetail, null, startTime, endTime, 0);
 }

 @Override
 public void schedule(JobDetail jobDetail, String name, Date startTime,
   Date endTime, int repeatCount) {
  schedule(jobDetail, name, startTime, endTime, 0, 0L);
 }

 @Override
 public void schedule(JobDetail jobDetail, Date startTime, Date endTime,
   int repeatCount, long repeatInterval) {
  schedule(jobDetail, null, startTime, endTime, repeatCount,
    repeatInterval);
 }

 @Override
 public void schedule(JobDetail jobDetail, String name, Date startTime,
   Date endTime, int repeatCount, long repeatInterval) {
  if (name == null || name.trim().equals("")) {
   name = UUID.randomUUID().toString();
  }

  try {
   scheduler.addJob(jobDetail, true);

   SimpleTrigger SimpleTrigger = new SimpleTrigger(name,
     Scheduler.DEFAULT_GROUP, jobDetail.getName(),
     Scheduler.DEFAULT_GROUP, startTime, endTime,
     repeatCount, repeatInterval);
   scheduler.scheduleJob(SimpleTrigger);
   scheduler.rescheduleJob(name, Scheduler.DEFAULT_GROUP,
     SimpleTrigger);
  } catch (SchedulerException e) {
   throw new RuntimeException(e);
  }
 }

 

 

几点说明:

1.由于本人在项目中使用的是EJB,所以这个类被定义为stateless bean 这样的好处是我quartz的接口不仅可以被本地访问,还可以被远程客户端访问。

2.@PostConstruct 这个注释规定了在这个bean被容易所管理并初始化的时候被调用的方法

也就是说

 private void initScheduler() {
  try {
   this.scheduler = StdSchedulerFactory.getDefaultScheduler();
   System.out.println("***The schedule init by ScheduleServiceImpl.class**");
  } catch (SchedulerException e) {
   e.printStackTrace();
  }
 }

这段代码在当这个类被初始化的时候,就已经执行了,看看schedule不就是我们想要的东西吗?呵呵

 

ScheduleService.java

 

package com.winmess.storesgate.schedule;

import java.util.Date;
import java.util.Map;

import org.quartz.CronExpression;
import org.quartz.JobDetail;
import org.springframework.scheduling.quartz.JobDetailBean;

public interface ScheduleService {
 /**
  * 根据 Quartz Cron Expression 调试任务
  * @param cronExpression  Quartz Cron 表达式,如 "0/10 * * ? * * *"等
  */
 void schedule(JobDetail jobDetail , String cronExpression);
 
 /**
  * 根据 Quartz Cron Expression 调试任务
  * @param name  Quartz CronTrigger名称
  * @param jobDetailName jobDetail名称
  * @param cronExpression Quartz Cron 表达式,如 "0/10 * * ? * * *"等
  */
 void schedule(JobDetail jobDetail , String name,String cronExpression);
 
 /**
  * 根据 Quartz Cron Expression 调试任务
  * @param cronExpression Quartz CronExpression
  */
 void schedule(JobDetail jobDetail , CronExpression cronExpression);
 
 /**
  * 根据 Quartz Cron Expression 调试任务
  * @param name Quartz CronTrigger名称
  * @param cronExpression Quartz CronExpression
  */
 void schedule(JobDetail jobDetail , String name,CronExpression cronExpression);
 
 /**
  * 在startTime时执行调试一次
  * @param startTime 调度开始时间
  */
 void schedule(JobDetail jobDetail , Date startTime); //限时抢购业务
 
 /**
  * 在startTime时执行调试一次
  * @param name Quartz SimpleTrigger 名称
  * @param startTime 调度开始时间
  */
 void schedule(JobDetail jobDetail , String name,Date startTime);
 
 /**
  * 在startTime时执行调试,endTime结束执行调度
  * @param startTime 调度开始时间
  * @param endTime 调度结束时间
  */
 void schedule(JobDetail jobDetail , Date startTime,Date endTime); 
 
 /**
  * 在startTime时执行调试,endTime结束执行调度
  * @param name Quartz SimpleTrigger 名称
  * @param startTime 调度开始时间
  * @param endTime 调度结束时间
  */
 void schedule(JobDetail jobDetail , String name,Date startTime,Date endTime);
 
 /**
  * 在startTime时执行调试,endTime结束执行调度,重复执行repeatCount次
  * @param startTime 调度开始时间
  * @param endTime 调度结束时间
  * @param repeatCount 重复执行次数
  */
 void schedule(JobDetail jobDetail , Date startTime,Date endTime,int repeatCount); 
 
 /**
  * 在startTime时执行调试,endTime结束执行调度,重复执行repeatCount次
  * @param name Quartz SimpleTrigger 名称
  * @param startTime 调度开始时间
  * @param endTime 调度结束时间
  * @param repeatCount 重复执行次数
  */
 void schedule(JobDetail jobDetail , String name,Date startTime,Date endTime,int repeatCount);
 
 /**
  * 在startTime时执行调试,endTime结束执行调度,重复执行repeatCount次,每隔repeatInterval秒执行一次
  * @param startTime 调度开始时间
  * @param endTime 调度结束时间
  * @param repeatCount 重复执行次数
  * @param repeatInterval 执行时间隔间
  */
 void schedule(JobDetail jobDetail , Date startTime,Date endTime,int repeatCount,long repeatInterval) ;
 
 /**
  * 在startTime时执行调试,endTime结束执行调度,重复执行repeatCount次,每隔repeatInterval秒执行一次
  * @param name Quartz SimpleTrigger 名称
  * @param startTime 调度开始时间
  * @param endTime 调度结束时间
  * @param repeatCount 重复执行次数
  * @param repeatInterval 执行时间隔间
  */
 void schedule(JobDetail jobDetail , String name,Date startTime,Date endTime,int repeatCount,long repeatInterval);
 

}

以上定义出一些常用的定时任务接口,这些工作完成也就意味着Quartz的应用框架已经搭建完毕了,接下来的就定义真正quartz要去执行的任务-task

public class ShoutTask extends QuartzJobBean implements Shout

 

 

public interface Shout extends Job

 

以上是定义任务接口,以及任务实现的基本接口,我就不再细化了。

好了,接下来就是我们如何将我们定义好的task放到quartz中去定时执行了。其实很简单,利用我们上面提到的一大堆接口,一句话就可以完成了。具体代码示例如下:

 

实现类

package com.winmess.storesgate.schedule.example;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;

import jee.jwapp.core.domain.service.BaseServiceImpl;

import org.quartz.JobDetail;
import org.quartz.Scheduler;

import com.winmess.storesgate.schedule.ScheduleService;

/**
 * @author xuxm E-mail: xuxm@winmess.com
 * @version 创建时间:2009-12-9下午02:07:40
 */
@Stateless
@Remote(ShoutService.class)
public class ShoutServiceBean extends BaseServiceImpl implements ShoutService{

 @EJB
 private ScheduleService scheduleService;
 
 public void shout(String startDate){
  Date startTime = this.parse(startDate);
  JobDetail jobDetail = new JobDetail("myjob",Scheduler.DEFAULT_GROUP,ShoutTask.class);
  scheduleService.schedule(jobDetail, null, startTime, null, 0, 0);
 }
 
 public void create(String star , String end){
  
 }
 
 private Date parse(String dateStr){
  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  try {
   return format.parse(dateStr);
  } catch (ParseException e) {
   throw new RuntimeException(e);
  }
 }
}

接口:package com.winmess.storesgate.schedule.example;

import jee.jwapp.core.domain.service.BaseService;

/**
 * @author xuxm E-mail: xuxm@winmess.com
 * @version 创建时间:2009-12-9下午02:07:49
 */
public interface ShoutService extends BaseService{

 public void shout(String startDate);
}

这个接口是为客户端调用的,当然,如果你使用的不是EJB,那么spring也同样支持这样的配置和架构。

 

希望我的这篇文章可以为大家在实际计划任务的项目中得到一些帮助和启发,更希望大家可以多提意见和新的研究思路,谢谢各位!

本人联系方式:

 

msn:spamatrix@hotmail.com

email:spamatrix@sina.com

 

 

 

 


配置到此结束。

看一下我们在实际代码中是如何来应用的

刚才说了quartz是依靠JMX注册到JBOSS并成为JBOSS服务中的一项组件的,获得Quartz的根也是需要通过JNDI来取得的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值