管中窥Quartz

来源:互联网 发布:怎么找淘宝差评师 编辑:程序博客网 时间:2024/06/08 17:07

前言

前段时间一个项目中又用到了定时任务功能,这次用到的是Quartz,所以这里是时候学习总结一下来,任务调度实现有很多中方案,像java原生的Java Timer,还有spring从spring3中定制的spring Task,其实具体的实现原理都是差不多的,但是里面还是有一些功能上的区别,这里主要和大家一起总结一下Quartz的使用,对于spring Task后面会和大家一起总结,这里也就不介绍Quartz的出生背景了,以及它有多牛逼,这些官网都有,想必我们这些码农的关注点也不是这里,我们主要是学会怎样在应用中实现任务调度功能,这里结合Quartz的原理和大致结构来和大家一起学习总结一下,因为个人能力有限,下面所总结的对于整个Quartz框架只是些基础知识,适合入门。对于稍微高档的什么集群配置,后面再和大家一起学习总结,所以下面的所总结的只能说是管中窥豹,略见一斑。

简单小例子

任务调度或者说是定时任务,在日常开发中经常使用,像定时推送数据,定时更新数据。。总之使用的频率还是挺高的,这里的小例子为了让大家从基础结构上了解Quratz,没有结合spring配置,是最基础的Quartz实现定时任务的小测试,配置定时任务之前需要引入Quartz所需要的jar,如果你是maven项目,那你只需要在pom.xml文件中注入Quartz相关的依赖,jar依赖关系见这里 http://www.quartz-scheduler.org/downloads/。
首先是一个实现Job接口的任务类,我们具体的定时操作都是在这个类中来实现的。代码如下

public class QuartzJob implements Job{    @Override    public void execute(JobExecutionContext context)            throws JobExecutionException {        // TODO Auto-generated method stub        JobDetail jobDetail=context.getJobDetail();        JobDataMap dataMap=jobDetail.getJobDataMap();        SimpleDateFormat smf=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");        System.out.println("你好,"+dataMap.get("name")+",定时任务开始执行,开始时间是"        +smf.format(new Date()));    }}

接着是调用测试的客户端,这里通过SchedulerFactory工厂生成对应的Scheduler,然后配置具体的触发器Trigger和JobDetail,以及JobDetail中的参数,具体代码如下

/**  * @ClassName: QuartzJobClient * @Description: 开始启动定时任务 * @author 爱琴孩*/public class QuartzJobClient {    public static void main(String[] args) {        //创建scheduler工厂类,并生成scheduler对象        SchedulerFactory factory = new StdSchedulerFactory();        Scheduler sche=null;        try {            sche = factory.getScheduler();        } catch (SchedulerException e1) {            // TODO Auto-generated catch block            e1.printStackTrace();        }         //先输出当前时间        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        System.out.println(format.format(new Date()));        //evenMinuteDateAfterNow是从现在起下一分钟        Date runTime = DateBuilder.evenMinuteDateAfterNow();        //分别创建JobDetail和Trigger对象        JobDetail job = JobBuilder.newJob(QuartzJob.class).usingJobData("name", "爱琴孩").build();        Trigger trigger = TriggerBuilder.newTrigger().startAt(runTime).build();        try {            //把任务和触发器加到scheduler中            sche.scheduleJob(job, trigger);              //开始任务            sche.start();        } catch (SchedulerException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        //这里让主线程暂停,等待定时任务执行完毕        try {            Thread.sleep(60*1000);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        try {            //sche.shutdown();            sche.shutdown(true);        } catch (SchedulerException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

上面的QuartzJob实现了Job接口,后面在运行时通过反射来获取对应的Job实例,每一个具体的定时任务对应一个Job实例。具体的演示结果如下
这里写图片描述

Quartz的大致结构

对于Quartz的整体结构,我们需要着重关注这几个核心点,以及他们之间是怎么样协同合作的,
* Job接口
对于Job接口,里面只要一个execute(JobExecutionContext context)方法,我们具体的定时任务都都要实现Job接口,然后重写里面的execute方法,在excute方法里面实现我们具体的定时操作任务逻辑,像日常开发中的增删改查。JobExecutionContext提供了一些定时任务执行时需要的信息,像上面从JobExecutionContext中获取Jobdetail,然后再从Job中获取JobDataMap。
* JobDetail
上面也说到对于具体的定时任务,每一个定时任务都需要实例化一个Job,在获取JobDetail的时候,传入一个Job的实现类,同时JobDetail中还保存了一些另外的定时任务执行信息,像任务描述,任务名和任务组。
* Trigger
对于Trigger,顾名思义,就是指定时任务的具体调用触发策略,什么时候开始执行定时任务,执行几次,每隔多长时间执行一次。在Quartz中主要有两个Trigger,第一个是SimpleTrigger,这个Trigger主要是适合固定频率执行的的定时任务,对于比较复杂的定时操作,主要使用CornTrigger,这个Trigger能够实现比较复杂的定时策略,像具体每个月具体几号定时执行定时任务。这里定时策略要使用具体的corn表达式来进行配置,由于篇幅问题,这里就不具体讲解corn表达式的使用。后面在spring和Quartz集成中再进行总结。
* Scheduler
Scheduler代表一个具体的任务调度容器,一个Scheduler中可以包含多个Job和多个Trigger。而一个Job可以对应多个Trigger,也就是说一个任务可以被多个Trigger触发执行,但是一个Trigger只能对应一个Job。当Job和Trigger注册到Scheduler容器之后,当scheduler容器启动之后,容器中注册的Job就会按照各自对应的Trigger触发策略进行执行。
* ThreadPool
Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。线程池的好处想必这里无需多言。对于ThreadPool的配置,我们可以可以使用property文件来进行配置,也可以在与spring集成中在xml文件中进行设置。
Job有一个StatefulJob子接口,代表有状态的任务,该接口是一个没有方法的标签接口,其目的是让Quartz知道任务的类型,以便采用不同的执行方案。无状态任务在执行时拥有自己的JobDataMap拷贝,对JobDataMap的更改不会影响下次的执行。而有状态任务共享共享同一个JobDataMap实例,每次任务执行对JobDataMap所做的更改会保存下来,后面的执行可以看到这个更改,也即每次执行任务后都会对后面的执行发生影响。正因为这个原因,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行,这意味着如果前次的StatefulJob还没有执行完毕,下一次的任务将阻塞等待,直到前次任务执行完毕。
上面几个核心点需要相互协调才实际上实现了定时任务。
这里写图片描述

总结

以上只是自己对于Quartz的一点小总结,后面再继续总结spring和Quartz的集成,这是在日常开发中经常使用的。
这里有一篇对于Quartz讲解比较好的文章,有需要的小伙伴们可以看看
Quartz使用总结 http://www.cnblogs.com/drift-ice/p/3817269.html

原创粉丝点击