最近项目中使用到了Quarz框架,本来考虑使用Springboot自带的Timer,但是貌似并不支持动态、灵活的cron表达式,所以三思之后还是使用了Quarz,话不多说,直接上手。
Quartz的maven依赖,这里推荐使用2.3.0的版本。
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
依赖加进之后,这里需要配置一下,创建一个quarz.properties,配置中可以把quarz.properties持久化到数据库中,也可以直接储存在内存中,这里无所谓,我是直接存储在内存中的。如果想开启持久化到数据库中,把注释打开就行。记得配置数据库的连接账号密码。
# 固定前缀org.quartz
# 主要分为scheduler、threadPool、jobStore、plugin等部分
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount = 2
# 优先级
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.misfireThreshold = 5000
# 默认存储在内存中
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#持久化
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#
#org.quartz.jobStore.tablePrefix = QRTZ_
#
#org.quartz.jobStore.dataSource = qzDS
#
#org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
#
#org.quartz.dataSource.qzDS.URL = jdbc:mysql://192.***.**.**:3306/database?
#useUnicode=true&characterEncoding=UTF-8
#
#org.quartz.dataSource.qzDS.user = root
#
#org.quartz.dataSource.qzDS.password =root
#
#org.quartz.dataSource.qzDS.maxConnections = 10
如果持久化到数据库。这里需要再依赖一个jar包,因为quarz是采用qzDS的方式去连接数据库
<dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.0.2</version> </dependency>
依赖配置都完成之后,开始写代码,首先创建一个SchedulerConfig的类用来注册bean,将Quarz的配置注册到容器中。
SchedulerConfig.java:
import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.io.IOException;
import java.util.Properties;
@Configuration
public class SchedulerConfig {
@Autowired
private MyJobFactory myJobFactory;
@Bean(name="SchedulerFactory")
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobFactory(myJobFactory);
factory.setQuartzProperties(quartzProperties());
return factory;
}
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
//在quartz.properties中的属性被读取并注入后再初始化对象
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
/*
* quartz初始化监听器
*/
@Bean
public QuartzInitializerListener executorListener() {
return new QuartzInitializerListener();
}
/*
* 通过SchedulerFactoryBean获取Scheduler的实例
*/
@Bean(name="Scheduler")
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
}
MyJobFactory.java:
这个类需要继承org.springframework.scheduling.quartz的AdaptableJobFactory类,实现createJobInstance()方法。这个方法主要是实现注入,创建一个Job实例。返回给SchedulerConfig.java中的setJobFactory()
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;
}
}
Controller,这里的参数不是传统的传递参数,需要创建JobDataMap, .put()方法实现值和参数的传递。
Quaz.class代表你的实现quarz调度方法的类。
withIdentity的两个参数一个代表实例名,和实例名
CronScheduleBuilder.cronSchedule("0/5 * * * * ?")这里要用到cron表达式,5秒执行一次。
@RequestMapping("/quartzRun")
public void quartzRun(@RequestParam("name")String name, @RequestParam("msg") String msg) throws SchedulerException {
SchedulerFactory sf = new StdSchedulerFactory();
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("name",name);
jobDataMap.put("msg",msg);
Scheduler sched = sf.getScheduler();
JobDetail job = newJob(Quaz.class).withIdentity("HelloJob", "group1").setJobData(jobDataMap).build();
CronTrigger trigger = newTrigger().withIdentity("HelloJob", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();
sched.scheduleJob(job, trigger);
scheduler.start();
}
servicesImpl:
需要实现package org.quartz Job接口下的execute()方法。
package com.jd.db.mydemodb.controller;
import com.jd.db.mydemodb.Entity.TestEntity;
import com.jd.db.mydemodb.service.BaseJob;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Service;
@Service
public class Quaz implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println(new Date());
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
System.out.println(jobDataMap.getString("name"));
System.out.println(jobDataMap.getString("msg"));
System.out.println(new Date());
}
}
然后通过context.getJobDetail().getJobDataMap()去获取Controller传过来的值,基本上所有类型就有。
注意:这里不知道是不是坑,我查了很多资料还是没有解决。比如你的Controller层使用@Autowired自动匹配查找某个实现类(@Service),然后你将这个自动匹配的这个类通过jobDataMap.put将值丢进去,那么你的impl会返回空指针异常,只能再Controller通过 service service = new ServicesImpl()的方式将其put进去比如:
但是如果你@Autowried Dao层,则可以直接put
最后一步,拿postman测试一下,看看结果如何
如果想要停止这个定时任务呢?只需要三句核心代码:
这里先停止,再删除,如果没有执行sched.deletejob,再次启动则需要更换之前的实例名和组名。
所以在这里,我们直接删除,之后还可以继续重新启动。
@RequestMapping("/pause")
public void pause(){
SchedulerFactory sf = new StdSchedulerFactory();
try {
Scheduler sched = sf.getScheduler();
sched.pauseJob(JobKey.jobKey("HelloJob", "group1"));
sched.deleteJob(JobKey.jobKey("HelloJob", "group1"));
} catch (SchedulerException e) {
e.printStackTrace();
}
System.out.println("ok");
}
试试看:
有不够好的还希望多指教,感谢。