Quartz是Java里流行的一种开源任务调度框架。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样简单复杂的日程表。Jobs可以做成标准的Java组件或 EJBs。本文会先大概介绍一下如何使用Quartz,然后重点是介绍实际项目里,通过二次开发,增加任务调度的可管理性和异常处理,使它具备一定的商业任务调度框架的功能(参考此文:http://www.fluxcorp.com/products/flux/technical/quartz.html)

Quartz要求一个任务必须实现接口Job的execute方法,如下一个简单的Job:

import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class SimpleJob implements Job {

public SimpleJob() {
    }

public void execute(JobExecutionContext context) throws JobExecutionException {
       
     try {
      
       Thread.sleep(1000*20);
      
     } catch (InterruptedException e) {
      
       e.printStackTrace();
     }

}
}

Quartz将任务和时间触发分开,因此,你还需要指定时间触发,通常采用Cron方式,如每天早上六点,也可以指定某个固定时间,如2008年8月8号等。

如以下即指定每天早上六点

CronTrigger cronTrigger = new CronTrigger("triggerName", "triggerGroup");
try {
   
    CronExpression cexp = new CronExpression("0 6 * * * ");    
    cronTrigger.setCronExpression(cexp);
} catch (Exception e) {
    e.printStackTrace();
}

Scheduler 类负责将时间触发指定给JobDetail,简单的来说JobDetail封装了你的任务,并可以提供任务名,所属组,以及附加的一些参数,代码如下:

SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
JobDetail job = new JobDetail("jobName", "groupName", SimpleJob.class);
Scheduler.scheduleJob(job, cronTrigger);

Job在被触发的时候,会通过反射实例化SimpleJob.class(因此你的Job必须有一个无参数的构造函数),并调用execute方法。

对于上列的SimpleJob,可以从execute方法输入参数context里获取一些属性,如任务名(如例子里的jobName),所在组(如:groupName).更重要的是,context里可以包含你指定的参数,如我们想让SimpleJob在运行的时候休眠时间为50秒,也可以这么写:

public void execute(JobExecutionContext context) throws JobExecutionException {
       
try {
   
    int sleep = context.getJobDetail().getJobDataMap().getInt("sleep");
    Thread.sleep(1000*sleep);
   
} catch (InterruptedException e) {
   
    e.printStackTrace();
}

}

参数Sleep将由调度框架传入,如下

SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
JobDetail job = new JobDetail("job1", "group1", SimpleJob.class);
job.getJobDataMap().put("sleep", 50);
Scheduler.scheduleJob(job, trigger);

如果你觉得本文写的不够详细,可以参考这个文档http://www.ibm.com/developerworks/cn/java/j-quartz/index.html,或者直接去官方网站http://wiki.opensymphony.com/display/QRTZ1/Tutorial 了解更多信息。

对于实际任务调度来说,Quartz只是提供了基本功能,摆在我们面前的仍然有一些需求Quartz并没有内置。如

任务状态管理:需要查看当前有哪些任务在运行,历史上任务执行情况

异常处理:任务出现异常需要告警,或者手工强制执行。

任务依赖关系:任务A执行前,任务B必须执行成功。

本文的下半部分将介绍如何实现这些功能,这也是我要写的重点.

首先,我们使用Annotation定义任务,如下一个任务

public class SimpleJob{

@Run
public void doit()
{
    try {   
       Thread.sleep(1000*20);   
    } catch (InterruptedException e) {  
       e.printStackTrace();
    }
}
}

也可以增加Stop,Pause,Resume等Annotation,在此略过

Annoatoin定义如下

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented

public @interface Run {

}

我倾向于用Annotation而不是接口是因为Annotation更灵活。比如一些传统的任务调度程序入口就是static main(String[] args)方法,只需要用Annotation指示一下,而且,Annoation扩展性也好,如给一个任务命名,可以扩展Annoatoin实现,如下;

@Run(name="com.simpleJob")
public void doit(String[] args)
{
    try {   
       Thread.sleep(1000*20);   
    } catch (InterruptedException e) {  
       e.printStackTrace();
    }
}
}

用Annoaton定义任务后,这任务如何加入到Quartz框架里?可以定义个新的Wrapper类,叫着JobWrapper,它是一个标准的Quartz的任务,即实现了接口Job ,当Quartz调用次类的时候,此类会根据DataMap里的BatchDescription描述来调用正确的任务。

BatchDescription很简单,有三个属性

private String className;
private String cron;
private String[] paramenters=null;

className,即为使用Annotation定义的任务。
cron即为Cron时间表达式
paramenters 为任务的参数.

JobWrapper 是系统的核心,Quartz调用它,它转而调用JobDescription描述的任务,多了这一层,就能很好的管理Job状态,做一些异常处理等更为复杂的任务管理了。代码如下:

public JobWrapper()
{
   // be used to persist to database or other features
   id = System.currentTimeMillis()+"_"+Thread.currentThread().getId();
stateChanged(id,JobStatus.INIT);
JobManager.instance().reg(this)

}

public void execute(JobExecutionContext context)
    throws JobExecutionException {
   JobDataMap data = context.getJobDetail().getJobDataMap();
    desc = (BatchDescription)data.get("JobData");
    runParameters = desc.getParamenter();  
   try {
    realJob = Class.forName(desc.getClassName()).newInstance();
   
   } catch (Exception e1) {

e1.printStackTrace();
     return ;
   }
   //look for the method with annotation Run
   runMethod = getRunMethod();
   //reg it ,then can get it later  
   try {
   
    stateChanged(id,JobStatus.RUNNING)   
    runMethod.invoke(realJob, runParameters);   
   stateChanged(id,JobStatus.RUNNING)
    } catch (IllegalArgumentException e) {
      //ignore
      e.printStackTrace();
      return ;
   } catch (IllegalAccessException e) {
     //ignore
      e.printStackTrace();
      return ;
   } catch (InvocationTargetException e) {
     Throwable ex = e.getTargetException();
     // handle exception ,now just put this exception to some queue
       stateChanged(id,JobStatus.EXCEPTOIN,ex.getMessage()) ;
      return ;   
   }
}

private void stateChanged(String id,JobStatus,String msg){

//此方法可以用来存储任务到数据库,以供查看状态,如:

JobDao.save(id,name,JobStatus,msg,new Date());

}

private Method getRunMethod()
{
   // first look up the method with run annotation,if not find,check the main method
   if(runMethod!=null){
    return runMethod;
   }
   
   Method[] methods = realJob.getClass().getDeclaredMethods();
   for(Method m:methods)
   {
   
    Annotation[] annos = m.getAnnotations();
    if(annos!=null&&annos.length!=0)
    {
     for(Annotation anno:annos)
     {
      //System.out.println(anno.annotationType());
      if(anno.annotationType()==com.joelli.batch.quartz.annotation.Run.class)
      {
      
       return m;
      }
     }
    }
   
   
   }
   // look for the method public static void main,let ignore it   
   return null;
}

最后,然我们看看Quartz如何调用此类

//定义一个任务,类为com.javamonkey.SimpleJob,参数为Null
BatchDescription batchDesc= new BatchDescription("com.javamonkey.SimpleJob","15 0/2 * * * ?",null);

JobDetail job1 = new JobDetail(batchDesc.getClassName()+ ".Job", "joelli", JobWrapper.class);
job1.getJobDataMap().put("JobData", batchDesc);
CronTrigger cronTrigger = new CronTrigger(batchDesc.getClassName()+ ".Trigger");
CronExpression cexp = new CronExpression("0 6 * * * ");    
cronTrigger.setCronExpression(cexp);
Scheduler.scheduleJob(job1, cronTrigger);

如上代码,Quartz在时间触发后,会实例话JobWrapper.class,并调用Execute方法。JobWrapper会根据BatchDescription获得真正要运行的任务并调用,同时,纪录任务状态以供管理。

转载于:https://www.cnblogs.com/muyuge/archive/2009/03/03/6152801.html

Quartz入门到精通相关推荐

  1. SpringBoot入门到精通 idea教学 (余胜军通俗易懂版本)

    Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过 ...

  2. SpringBoot从入门到精通教程(三十一)- 爬虫框架集成

    需求背景 SpringBoot用法:爬虫框架集成 业务场景 以抓取"今日头条"新闻举例说明 技术点 1. 集成爬虫框架webmagic(更多了解webmagic,可以去官方地址) ...

  3. Java学习路线-五大步骤让你入门到精通

    一.基础教程 Java基础是java初学者的起点,是帮助你从小白入门到精通必学基础课程! 为初学者而著! java300集>>>适合准备入行开发的零基础员学习Java,基于最新JDK ...

  4. Spring入门到精通:第一章 基础入门:1.Spring框架概述

    Spring入门到精通:第一章 基础入门:1.Spring框架概述 前言:为什么要学习Spring框架? 为什么要学习Spring框架呐? (1)使用广泛:现在很多的企业都有Spring的影子,不管是 ...

  5. java从入门到精通学习路线

    目前Java在许多行业的客户端方面的应用非常多,比如OA.邮箱.投票.金融.考试.物流.医疗.矿山等信息方面的系统.Java开发者在这方面的需求也非常大,待遇也相当不错,工资水平可能和Java互联网方 ...

  6. java从入门到精通_想要开始学java?你要的java从入门到精通布列如下!

    java从入门到精通,让我来告诉你! 毫无疑问,java是当下最火的编程语言之一.对于许多未曾涉足计算机编程的领域「小白」来说,深入地掌握java看似是一件十分困难的事.其实,只要掌握了科学的学习方法 ...

  7. 虚幻引擎5(UE5)实时VFX游戏特效制作入门到精通

    UE5 Niagara学习教程  课程获取:虚幻引擎5(UE5)实时VFX游戏特效制作入门到精通-云桥网 你会学到什么 我将通过创建各种各样的实时效果来教你虚幻引擎中强大的粒子系统. 我们将从简单的基 ...

  8. Revit:从入门到精通学习教程

    流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,48.0 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确) |大小:8.07 GB |时长:12h 16m Re ...

  9. 《Java 开发从入门到精通》—— 2.2 编写第一段Java程序

    本节书摘来异步社区<Java 开发从入门到精通>一书中的第2章,第2.2节,作者: 扶松柏 , 陈小玉,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.2 编 ...

  10. meteor从入门到精通_我已经大规模运行Meteor一年了。 这就是我所学到的。

    meteor从入门到精通 by Elie Steinbock 埃莉·斯坦博克(Elie Steinbock) 我已经大规模运行Meteor一年了. 这就是我所学到的. (I've been runni ...

最新文章

  1. 【每日一题】二分查找
  2. 4. 分类的线性模型
  3. Ubuntu用命令行发邮件mutt,报警发短信通知
  4. 写一个脚本定时自动备份mysql到指定目录
  5. Windows 下目录及文件向Linux同步
  6. opencv imread后做resizie_opencv第1课-加载、修改、保存图像
  7. springmvc与mysql实例_Spring+Mybatis+SpringMVC+Maven+MySql搭建实例
  8. SpringCloud微服务架构学习(二)常见的微服务架构
  9. javaweb系统oracle锁表,oracle、websphere下获取数据库连接时出现死锁
  10. 如何最快速的找到页面某一元素所绑定的点击事件,并查看js代码
  11. 离散数学及其应用傅彦pdf_离散数学及其应用 傅彦 等 高等教育出版社
  12. Python查看函数源码
  13. 鸟哥的Linux私房菜(基础学习篇第四版)学习笔记
  14. 使用Pr给视频添加字幕
  15. linux如何查看路由器ip地址,如何查找路由器IP地址?
  16. 百度Java后端实习面试
  17. Word、PPT、PDF 文件怎么批量插入首页、扉页、尾页?怎么在指定位置插入页?
  18. 1.一条SQL语句如何执行
  19. 前端开箱即用的中后台管理模版,建议收藏
  20. 2021-08-23-Nginx安装与部署项目

热门文章

  1. jQuery调用或获取iframe中的方法或控件值
  2. akamai 指纹 和 akamai BMP 移动端sensor 风控分析
  3. CentOS安装MySQL及其使用(总结整理)
  4. std::thread参数传递包含引用时的注意事项
  5. Spring之事务控制
  6. 深入理解计算机系统第四版_深入理解计算机系统第三版2.4节中文版的一处翻译问题及英文版可能的一处错误...
  7. 数据结构——>二叉树
  8. JavaWeb:生成简单随机图片验证码返回给客户端
  9. ElementUI:input表单验证
  10. crawler4j源码学习(2):Ziroom租房网房源信息采集爬虫