参考:http://blog.youkuaiyun.com/evankaka/article/details/45361759
http://www.cnblogs.com/hafiz/p/6159280.html
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/
cron表达式:http://www.cnblogs.com/linjiqin/archive/2013/07/08/3178452.html
基本介绍和核心接口
(1)quartz是完全基于java的可用于进行定时任务调度的开源框架,使用的时候需要引入:
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
(2)核心接口包括:
- Job: 就是要执行的任务,该接口只有一个方法execute(JobExecutionContext jobExecutionContext)方法,Job运行时的信息保存在JobDataMap中(JobDataMap下面介绍)
- JobDetail: 定义Job的实例。接收Job名字、描述以及Job类等信息
- Trigger: 触发Job运行的东西,主要包括四类:SimpleTriger、CronTrigger、DateIntervalTrigger和NthIncludeDayTrigger,目前常用的是前两种
- JobBuilder: 定义和创建JobDetail实例的接口
- TriggerBuilder: 定义和创建Trigger实例的接口
- Scheduler: quartz的运行容器,Trigger和JobDetail可以注册到scheduler中,两者在Scheduler中拥有各自的组及名称(组及名称是Scheduler查找定位容器中某一对象的依据),Trigger和JobDetail的组合名称都必须唯一,但是两者的组和名称可以相同,因为它们是不同类,一个job可以对应多个trigger,但是一个trigger只能对应一个job
注意:
传递给scheduler的是JobDetail而不是Job,JobDetail通过接收到的有关Job的信息,使用反射机制实例化Job,并且每次Job执行完之后,Job class的实例会被丢弃,Jvm的垃圾回收器会将他们回收.通过这些介绍,所以Job实例实现时,需要注意以下几点:
- 它必须具有一个无参构造函数
- 它不应该有静态数据类型。因为每次job实例执行完之后便被回收,而静态成员变量因为依附于类存在,并不能被回收,如果静态变量的值被某个类修改,它的值就没法被保护
这些接口的关系图如下:
线程
在Quartz中,有两类线程,Shceduler调度线程和任务执行线程,前者包括普通任务调度和Misfire任务调度(Misfire见这里后者需要一个线程池维护,调度图如下:
传递数据
尽管Job类不好定义静态变量,但是可以通过JobDataMap传递数据,JobDataMap是JobDetail的成员变量,可以借助JobDataMap为Job实例提供属性/配置,可以通过它来追踪Job的执行状态等等。对于第一种情况,可以在创建Job时,添加JobDataMap数据,在Job的execute()中获取数据(参见下面simpleTrigger的使用实例)第二种,则可以在Listener中通过获取JobDataMap中存储的状态数据追踪Job的执行状态(这个不是很懂)。
使用实例
1、SimpleTrigger
Job类:
public class SimpleQuartzJob implements Job {
public SimpleQuartzJob(){}
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("In SimpleQuartzJob - executinog its JOB at " + new Date() + "by" +
jobExecutionContext.getMergedJobDataMap().get("testKey") + " " +
jobExecutionContext.getJobDetail().getJobDataMap().get("testKey") + " " +
jobExecutionContext.getJobDetail().getKey() + "\n" +
jobExecutionContext.getJobDetail().toString()
);
jobExecutionContext.getMergedJobDataMap().put("state",1);
}
}
执行测试:
public class SimpleTriggerTest {
public static void main(String[] args) throws SchedulerException {
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
//获取scheduler
Scheduler scheduler = schedulerFactory.getScheduler();
//定义jobDetail
JobDetail job = JobBuilder.newJob(SimpleQuartzJob.class).withIdentity("simpleJob", "group2").build();
job.getJobDataMap().put("testKey", "vava");
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("tigger1", "group1").startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)
.withRepeatCount(10)).build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
}
}
最后输出:
2、CronTrigger
结合Spring使用,首先引入一依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.2.6.RELEASE</version>
</dependency>
在这里,配置Job有两种方式:
(1)利用JobDetailBean包装QuartJobBean子类(即Job类)的实例,这种方式可以给作业传递数据
(2)利用MethodInvokiingJobDetailFactoryB工厂Bean包装普通的Java对象(即Job类)
- 采用第一种方法创建Job类,一定要继承QuartzJobBean,实现executeInternal(JobExecutionContextjobexecutioncontext)方法,此方法就是被调度任务的执行体,然后将此Job类的实例直接配置到JobDetailBean中即可。这种方法和在普通的Quartz编程中是一样的。
- 采用第二种方法创建Job类,无须继承父类,直接配置MethodInvokingDetailFactoryBean即可,但需要指定一些属性:
(1)targetObject:指定包含任务执行体的Bean实例。
(2)targetMethod:指定Bean实例的该方法包装成任务的执行体
(3)concurrent(可选):是否并发进行,false表示不可以并发
例子:
方式一:
job实例:
public class CronQuartzJob extends QuartzJobBean {
private static final Logger logger = LoggerFactory.getLogger(CronQuartzJob.class);
private Integer timeout;
public void setTimeout(Integer timeout){
this.timeout = timeout;
}
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
logger.info("CronTrigger类型任务进行中....");
System.out.println(timeout);
}
}
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="secondCron" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="cron.CronQuartzJob"/>
<property name="jobDataAsMap">
<map>
<entry key="timeout" value="90"/>
</map>
</property>
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="secondCron"/>
<property name="cronExpression" value="0 50 18 * * ?"/>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" id="scheduler">
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
</bean>
</beans>
执行测试类:
public class CronTriggerTest {
public static void main(String[] args) throws SchedulerException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
执行结果:
可以看到,在配置文件中传入了参数timeout在job中得到了执行
方式二
job实例:
public class CronQuartzJob2 {
private static final Logger logger = LoggerFactory.getLogger(CronQuartzJob2.class);
public void executeJob() {
logger.info("cronQuartzJob 正在运行");
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="thirdCron" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<bean class="cron.CronQuartzJob2"/>
</property>
<property name="targetMethod" value="executeJob"/>
<!--作业不并发调度 -->
<property name="concurrent" value="false"/>
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="JobDetail" ref="thirdCron"/>
<property name="cronExpression" value="0 46 18 * * ?"/>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
</bean>
</beans>
执行结果: