一、Quartz简介
Quartz大致可分为三个主要的核心:
1、调度器Scheduler:是一个计划调度器容器,容器里面可以盛放众多的JobDetail和Trigger,当容器启动后,里面的每个JobDetail都会根据Trigger按部就班自动去执行 .
2、任务Job:要执行的具体内容。JobDetail:具体的可执行的调度程序,包含了这个任务调度的方案和策略。
3、触发器Trigger:调度参数的配置,什么时候去执行调度。
原理:
可以这么理解它的原理:调度器就相当于一个容器,装载着任务和触发器。任务和触发器又是绑定在一起的,然而一个任务可以对应多个触发器,但一个触发器却只能对应一个任务。当JobDetail和Trigger在scheduler容器上注册后,形成了装配好的任务作业(JobDetail和Trigger所组成的一对儿),就可以伴随容器启动而调度执行了。
二、与spring的整合
本文的用的是quartz-2.2.1与spring-3.2.2。之所以在这里特别对版本作一下说明,是因为spring和quartz的整合对版本是有要求的。 spring3.1以下的版本必须使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然会出错。 原因主要是:spring对于quartz的支持实现,org.springframework.scheduling.quartz.CronTriggerBean继承了 org.quartz.CronTrigger,在quartz1.x系列中org.quartz.CronTrigger是个类,而在 quartz2.x系列中org.quartz.CronTrigger变成了接口,从而造成无法用spring的方式配置quartz的触发器 (trigger)。
spring中使用quartz有两种方式,具体请看 http://blog.csdn.net/liuxiao723846/article/details/46879077
三、动态整合
上面的整合只能应付简单的需求,但很多时候我们遇到的是需要动态的添加、暂停、修改任务。而spring中所提供的定时任务组件却只能够通过修改xml中trigger的配置才能控制定时任务的时间以及任务的启用或停止,这在带给我们方便的同时也失去了动态配置任务的灵活性。
所以我们就得换种方式来解决。把任务与cronExpression存放在数据库中,最大化减少xml配置,创建一个工厂类,在实际调用时把任务的相关信息通过参数方式传入,由该工厂类根据任务信息来具体执行需要的操作,从而方便我们的动态修改。
Maven
<!-- quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>1.spring配置(其实只要这一行足矣,去掉了原先"taskJob"、"myTrigger"等配置):
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" />
2. 任务执行入口( 就是在这里执行quartz容器中的任务的 ),实现Job接口,类似工厂类:
package com.es.quartz;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import com.es.entry.ExportTask;
import com.es.service.TaskExportService;
import com.es.utils.exception.BusinessException;
/**
* 定时任务运行工厂类
* @author Administrator
*Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行, 如果定时任执行太长,会长时间占用资源,导致其它任务堵塞。
1.在Spring中这时需要设置concurrent的值为false, 禁止并发执行。
<property name="concurrent" value="true" />
2.当不使用spring的时候就需要在Job的实现类上加@DisallowConcurrentExecution的注释
设置@DisallowConcurrentExecution以后程序会等任务执行完毕以后再去执行,否则会在3秒时再启用新的线程执行
*/
@DisallowConcurrentExecution
public class QuartzJob implements Job {
private Logger myLogger = LogManager. getLogger ( "QuartzJobFactory" );
@Autowired
private TaskExportService taskExportService ;
@Override
public void execute(JobExecutionContext context ) throws JobExecutionException {
try {
ExportTask task = (ExportTask) context .getJobDetail().getJobDataMap().get( "task" );
// context.getJobDetail().getJobDataMap().v
myLogger .info( task .getName()+ ":任务成功运行" );
if ( "exact" .equals( task .getSearchType())){
taskExportService .runTaskAutomaticForExact( task );
}
} catch (BusinessException e ) {
e .printStackTrace();
}
myLogger .info( "任务成功运行完成" );
}
}
3、 创建任务类。既然要动态修改任务,那任务就得保存在某个地方。一个po类
package com.es.entry;
public class ExportTask {
private Integer id ;
private String name ; //任务名
private String export_cron ; // cron 表达式
private String start_time ; //开始时间
private String run_time ; //运行时长
private Integer status ; //'状态(0:未运行,1:运行中,2:运行完成)
private String file_url ; //文件地址
private String params ; //查询参数
private Integer type ; //调用类型(0:手动,1:周期)
private String searchType ; //检索类型
private Integer createUserId ; //创建人id
public Integer getId() {
return id ;
}
public void setId(Integer id ) {
this . id = id ;
}
public String getName() {
return name ;
}
public void setName(String name ) {
this . name = name ;
}
public String getExport_cron() {
return export_cron ;
}
public void setExport_cron(String export_cron ) {
this . export_cron = export_cron ;
}
public String getStart_time() {
return start_time ;
}
public void setStart_time(String start_time ) {
this . start_time = start_time ;
}
public String getRun_time() {
return run_time ;
}
public void setRun_time(String run_time ) {
this . run_time = run_time ;
}
public Integer getStatus() {
return status ;
}
public void setStatus(Integer status ) {
this . status = status ;
}
public String getFile_url() {
return file_url ;
}
public void setFile_url(String file_url ) {
this . file_url = file_url ;
}
public String getParams() {
return params ;
}
public void setParams(String params ) {
this . params = params ;
}
public Integer getType() {
return type ;
}
public void setType(Integer type ) {
this . type = type ;
}
public String getSearchType() {
return searchType ;
}
public void setSearchType(String searchType ) {
this . searchType = searchType ;
}
public Integer getCreateUserId() {
return createUserId ;
}
public void setCreateUserId(Integer createUserId ) {
this . createUserId = createUserId ;
}
}
4.在这里进行任务的增删改查
接口:
package com.es.quartz;
import java.util.List;
import com.es.entry.ExportTask;
import com.es.utils.exception.BusinessException;
public interface QuartzManager {
/**
* 向容器中添加任务
* @param task
* @throws BusinessException
*/
public void addJob(ExportTask task ) throws BusinessException;
/**
* 从容器中删除任务
* @param jobnames
* @throws BusinessException
*/
public void removeJob(List<String> jobnames ) throws BusinessException;
}
实现类:
package com.es.quartz.impl;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import com.es.entry.ExportTask;
import com.es.quartz.QuartzJob;
import com.es.quartz.QuartzManager;
import com.es.utils.exception.BusinessException;
@Component
public class QuartzManagerImpl implements QuartzManager {
private Logger log = LogManager. getLogger ( "QuartzManagerImpl" );
@Autowired
private SchedulerFactoryBean schedulerFactoryBean ;
@Override
public void addJob (ExportTask task ) throws BusinessException {
log .info( "addJob start:" +( task .getName()+ "@" + task .getId()));
Scheduler scheduler = schedulerFactoryBean .getScheduler();
//任务构建withIdentity:相当于给任务起了个名字
JobDetail jobDetail =JobBuilder. newJob (QuartzJob. class ).withIdentity( new JobKey( task .getName()+ "@" + task .getId())).build();
jobDetail .getJobDataMap().put( "task" , task );
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder. cronSchedule ( task .getExport_cron());
//按新的cronExpression表达式构建一个新的trigger:withIdentity:相当于给trigger起了个名字
CronTrigger trigger = TriggerBuilder. newTrigger ().withSchedule( scheduleBuilder ).withIdentity( new TriggerKey( task .getName()+ "@" + task .getId())).build();
try {
scheduler .scheduleJob( jobDetail , trigger );
} catch (SchedulerException e ) {
throw new BusinessException( e , ( task .getName()+ "@" + task .getId())+ ":quartz添加job异常" );
}
}
@Override
public void removeJob (List<String> jobnames ) throws BusinessException {
log .info( "removeJob start :" + jobnames .size());
if ( null == jobnames || jobnames .isEmpty()){
throw new BusinessException( jobnames + ":quartz删除job 参数异常" );
}
Scheduler scheduler = schedulerFactoryBean .getScheduler();
try {
for (String name : jobnames ){
scheduler .pauseTrigger( new TriggerKey( name )); // 停止触发器
scheduler .unscheduleJob( new TriggerKey( name )); //移除触发器
scheduler .deleteJob( new JobKey( name )); //删除任务
}
} catch (SchedulerException e ) {
throw new BusinessException( e , jobnames + ":quartz删除job异常" );
}
}
}
5.quartz的Job中注入spring对象
一般情况下,quartz的job中使用autowired注解注入的对象为空,这时候我们就要使用spring-quartz提供的AdaptableJobFactory类自定义一个类:
package com.es.quartz;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
/**
* 一般情况下,quartz的job中使用autowired注解注入的对象为空,
* 这时候我们就要使用spring-quartz提供的AdaptableJobFactory类。
* @author Administrator
*
*/
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
然后将spring中配置改为如下:
<!-- quartz -->
< bean id = "jobFactory" class = "com.es.quartz.JobFactory" ></ bean >
< bean id = "schedulerFactoryBean" class = "org.springframework.scheduling.quartz.SchedulerFactoryBean" >
< property name = "jobFactory" ref = "jobFactory" ></ property >
</ bean >
这时候我们就可以在Job的实现类中使用autowired注入service对象了,如 QuartzJob类。
版权声明:本文为qq_35153200原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。