Spring Boot 整合 Quartz 实现定时任务
1,添加Maven依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
2,新建一个MyJobFactory
这里我们需要注意 我注入了一个 自定义的JobFactory ,然后 把其设置为SchedulerFactoryBean 的 JobFactory。其目的是因为我在具体的Job 中 需要Spring 注入一些Service。
所以我们要自定义一个jobfactory, 让其在具体job 类实例化时 使用Spring 的API 来进行依赖注入。
MyJobFactory 具体实现:
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;
import org.springframework.stereotype.Component;
@Component
public class MyJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
3,新建一个QuartzConfig
添加 QuartzConfig 类 来声明相关Bean
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@Configuration
public class QuartzConfig {
@Autowired
private MyJobFactory myJobFactory;
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setJobFactory(myJobFactory);
System.out.println("myJobFactory:"+myJobFactory);
return schedulerFactoryBean;
}
@Bean
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}
}
4,新建一个QuartzManager
在其他类中调用本类中的addJob方法进行任务添加
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.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
/**
*
* @author QQ:1535512395
*
*/
public class QuartzManager {
@Autowired
private Scheduler scheduler;
/**
* 功能: 添加一个定时任务
*
* @param jobName
* 任务名
* @param jobGroupName
* 任务组名
* @param triggerName
* 触发器名
* @param triggerGroupName
* 触发器组名
* @param jobClass
* 任务的类类型 eg:TimedMassJob.class
* @param cron
* 时间设置 表达式,参考quartz说明文档
* @param objects
* 可变参数需要进行传参的值
*/
public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
Class jobClass, String cron, Object... objects) {
try {
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
System.out.println("jobDetail.getKey:"+jobDetail.getKey());
// 触发器
if (objects != null) {
for (int i = 0; i < objects.length; i++) {
// 该数据可以通过Job中的JobDataMap dataMap =
// context.getJobDetail().getJobDataMap();来进行参数传递值
jobDetail.getJobDataMap().put("data" + (i + 1), objects[i]);
}
}
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
scheduler.scheduleJob(jobDetail, trigger);
// 启动
if (!scheduler.isShutdown()) {
scheduler.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能:修改一个任务的触发时间
*
* @param jobName
* @param jobGroupName
* @param triggerName
* 触发器名
* @param triggerGroupName
* 触发器组名
* @param cron
* 时间设置,参考quartz说明文档
*/
public void modifyJobTime(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
String cron) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
scheduler.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能: 移除一个任务
*
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
*/
public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
// 停止触发器
scheduler.pauseTrigger(triggerKey);
// 移除触发器
scheduler.unscheduleJob(triggerKey);
// 删除任务
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
System.out.println("removeJob:"+JobKey.jobKey(jobName));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
*
* 功能:启动所有定时任务
*/
public void startJobs() {
try {
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能:关闭所有定时任务
*/
public void shutdownJobs() {
try {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
5,工具类,日期转换cron表达式时间格式
import java.text.SimpleDateFormat;
import java.util.Date;
public class QuartzCronDateUtils {
/***
* 功能描述:日期转换cron表达式时间格式
*
* @param date
* @param dateFormat
* : e.g:yyyy-MM-dd HH:mm:ss
* @return
*/
public static String formatDateByPattern(Date date, String dateFormat) {
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
String formatTimeStr = null;
if (date != null) {
formatTimeStr = sdf.format(date);
}
return formatTimeStr;
}
/***
* convert Date to cron ,eg. "14 01 17 22 07 ? 2017"
*
* @param date:时间点
* @return
*/
public static String getCron(java.util.Date date) {
String dateFormat = "ss mm HH dd MM ? yyyy";
return formatDateByPattern(date, dateFormat);
}
public static void main(String[] args) {
QuartzCronDateUtils s = new QuartzCronDateUtils();
s.getCron(new Date());
System.out.println(s.getCron(new Date()));
}
}
6,监听器
自定义一个监听类,Quartz的job在项目重启时,job都失效了,把每次启动的job都存放在数据库,然后项目启动时监听器读取数据库的job,然后添加job。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.quartz.Job;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.yj.until.QuartzManager;
/**
* 容器监听器
* @author QQ 1535512395
*/
public class QuartzJobListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent arg0) {
/***处理获取数据库的job表,然后遍历循环每个加到job中 ***/
QuartzManager quartzManager = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(QuartzManager.class);
//此处就不写获取数据库了,模拟一个集合遍历的数据
List<Map<String,Object>> listMap=new ArrayList<>();
Map<String, Object> map1=new HashMap<String, Object>();
map1.put("jobClass","com.yj.quartzjob.QuartzJob");
map1.put("jobName","job1");
map1.put("jobGroupName","job1");
map1.put("jobTime","0/5 * * * * ? ");
listMap.add(map1);
for (Map<String, Object> map : listMap) {
try {
quartzManager.addJob((Class<? extends Job>)(Class.forName((String)map1.get("jobClass")).newInstance().getClass()),(String)map.get("jobName"), (String)map.get("jobGroupName"),(String)map.get("jobTime"));
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("QuartzJobListener 启动了");
}
public void contextDestroyed(ServletContextEvent arg0) {
}
}
7,具体测试实例调用,不会再抛空指针异常
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
@Component
public class HelpCutoffTimeJobNew implements Job {
@Autowired
private SharesMapper sharesMapper;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
String jobName = context.getJobDetail().getKey().toString().substring(8);
System.out.println(jobName+"问题结算定时任务开启..");
//更新job的执行状态
sharesMapper.updateJobStatus(jobName);
System.out.println(jobName+"问题结算定时任务结束..");
}
}