简单的了解了一下Quartz,发现实现定时任务有两种方法:一种是实现接口,一种是配置文件。
一、实现接口
package cn.manmanda.api.jobs;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.manmanda.core.news.utils.Global;
import static org.quartz.JobBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
/**
* 定时任务
* @date 2017-08-17
* @author ericzhan1993
* @version 1.0
*/
public class QuartzJobUtil implements Job{
// 使用quartz, 需要被实例化, 可以用SchedulerFactory来实现
private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();// Scheduler的创建和管理
private static Date date = new Date();
/**
* 重写Job接口的方法
* 注意: 实现类一定要是public类, 不能是内部类, 不然会报无法实例化的错误
*/
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {// 执行延时推送消息定时任务
System.out.println("定时任务开始执行...");
}
/**
* 新增任务
* @date 2017-08-17
* @author ericzhan1993
* @version 1.0
*/
public static void addJob() {// 添加一个延时任务
try {
Scheduler sched = gSchedulerFactory.getScheduler();// 得到调度器实例化Scheduler
// 注: 2.x.x版本的quartz和1.x.x版本的调用接口不一样
// 创建具体任务: 参数: (实现Job接口的类, 任务名, 任务组名)
JobDetail jobDetail = newJob(QuartzJobUtil.class).withIdentity("jobname", "jobInGroupName").build();
// 创建触发器: 绑定job和sched并设置一些参数, 一些方法参考api: http://www.quartz-scheduler.org/api/2.1.7/index.html
// 每隔1秒, 执行一次, 永久重复执行
Trigger trigger = newTrigger().withIdentity("jobname", "jobInGroupName").startNow().withSchedule(simpleSchedule()
.withIntervalInSeconds(1).repeatForever()).build();
// 设置触发器名和触发器组名, 供查询
trigger.getTriggerBuilder().withIdentity("triggerName", "triggerInGroupName");
// 规定在某时间执行, 可以用来做延迟任务
// time单位: 毫秒 延迟10秒
date.setTime(date.getTime() + 10 * 1000);
SimpleTrigger trigger2 = (SimpleTrigger) newTrigger().withIdentity("jobname", "jobInGroupName").startAt(date).build();
sched.scheduleJob(jobDetail, trigger);
// sched.scheduleJob(jobDetail, trigger2);
sched.start();// 执行
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
addJob();
}
}
因为时间的关系,只写了增加,别的以后补上。
1. 遇到的坑
①. 类无法被实例化
org.quartz.SchedulerException: Problem instantiating class ‘xxx’
本来想图个省事,弄个内部类实现接口,运行的时候发现报错,查官方文档发现:实现Job接口的类必须是public的。
②. spring注入失败:在重写的方法中无法调用service方法
java.lang.NullPointerException
at cn.manmanda.api.jobs.QuartzJobUtil.execute(QuartzJobUtil.java:49)
错误指向的是service接口引用的方法,可能是因为实现Job接口的execute()重写导致spring @Autowired注解注入的变量无法使用,在网上找了一些方法,是需要手动注入spring+配置xml(bean)的,我觉得非常麻烦,一定有更好的方法,于是我尝试了JobDataMap类,把spring注入成功的service变量传入execute(),结果成功了,不过还是期待更简洁的方法,如果有可以告诉我。
// dataMap的使用
JobDataMap dataMap = jobDetail.getJobDataMap();
dataMap.put("key", valueObj);// 创建job时使用
Object obj = (Object)context.getJobDetail().getJobDataMap().get("key");// 重写Job接口时使用
二、配置文件
<?xml version='1.0' encoding='utf-8'?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 使用MethodInvokingJobDetailFactoryBean,任务类可以不实现Job接口,通过targetMethod指定调用方法 -->
<!-- 让spring来自动管理quartz -->
<bean id="schedulerFactoryBean" name="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
<property name="triggers">
<list>
<ref bean="myTriggersA"></ref>
<ref bean="update"></ref>
<ref bean="update1"></ref>
<!-- <ref bean="update2"></ref> -->
</list>
</property>
<property name="autoStartup" value="true"></property>
</bean>
<!-- quartz类型 -->
<bean id="myTriggersA" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 配置JobDetail类 -->
<property name="jobDetail" ref="myJobDetailA" />
<property name="cronExpression">
<value>0 0 0 * * ?</value><!-- 配置定时时间 -->
</property>
</bean>
<bean id="myJobDetailA" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 配置你的实现类 -->
<property name="targetObject" ref="myJobA"></property>
<!-- 配置你的实现方法 -->
<property name="targetMethod" value="work"></property>
<property name="concurrent" value="false" />
</bean>
<bean id="myJobA" class="cn.manmanda.api.jobs.IndentJob"></bean>
</beans>
然后你的实现类:
public class IndentJob {
public void work(){
// 代码逻辑
// 按照配置文件的类和方法自动执行
}
}