赞
踩
springboot内置有org.springframework.scheduling.annotation.Scheduled可以让我们进行简单快速的任务调度(例如定时执行的任务),当我们一些和任务调度有关的业务开始复杂的时候,极其需要非常灵活的任务调度策略;在这种情况,博主使用了quartz,写下此文以记;
compile group: 'org.quartz-scheduler', name: 'quartz', version: '2.2.1'
springboot中集成quartz并进行持久化配置,在springboot项目中的resources目录下创建properties文件(和springboot的配置文件同级),命名quartz.properties;
内容如下:
# 固定前缀org.quartz # 主要分为scheduler、threadPool、jobStore、plugin等部分 # #实例名 org.quartz.scheduler.instanceName=TioadScheduler #实例id(唯一,有缺省值) org.quartz.scheduler.instanceId=TioadSchedulerId 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=5 # 优先级 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 #dev(第一次初始化quartz,需要执行quartz包下的sql,创建表结构) org.quartz.dataSource.qzDS.URL=持久化的数据库url配置 org.quartz.dataSource.qzDS.user=持久化的数据库连接用户账号配置 org.quartz.dataSource.qzDS.password=持久化的数据库连接用户密码配置 org.quartz.dataSource.qzDS.maxConnections=10
从官网下载对应版本的quartz,解压,目录下的docs/dbTables会有大多数数据库的建表语句,执行建表;
import org.quartz.Scheduler; import org.quartz.ee.servlet.QuartzInitializerListener; 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 TioadJobFactory tioadJobFactory;//注入我们自己的factory,防止无法在job中注入service层 @Bean(name="TioadSchedulerFactory") public SchedulerFactoryBean tioadSchedulerFactoryBean() throws IOException { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setQuartzProperties(quartzProperties()); // schedulerFactoryBean.setJobFactory(tioadJobFactory); return schedulerFactoryBean; } @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="TioadScheduler") public Scheduler scheduler() throws IOException { return tioadSchedulerFactoryBean().getScheduler(); }
实现quartz的job接口,重写execute(),这里就是任务的逻辑,在execute()中执行的任务逻辑如果用到service层,发现注入不成功的话,需要在上面的SchedulerConfig.class中set我们自己的;
import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Date; @Component public class Job1 implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss"); System.out.println("job 1 " + sdf.format(new Date())); } }
我们自己的工厂防止无法注入问题TioadJobFactory
@Component
public class TioadJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance); //这一步解决不能spring注入bean的问题
return jobInstance;
}
}
controller级测试使用quartz
import com.crm.restapi.param.QuartzParam; import com.crm.restapi.result.ApiResult; import org.quartz.*; import org.quartz.impl.matchers.GroupMatcher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.HashMap; import java.util.Set; import static org.quartz.CronScheduleBuilder.cronSchedule; import static org.quartz.JobBuilder.newJob; import static org.quartz.TriggerBuilder.newTrigger; @Validated @RequestMapping(value = "/task") @RestController public class TaskController extends BaseController{ @Autowired @Qualifier("TioadScheduler")//这里是config里面定义的scheduler,通过添加注解@Qualifier,使@Autowired的自动注入由bytype变为byname private Scheduler scheduler; @Value("${quartzname}") private String quartzname;//这是我自己定义的quartzname,这里是字符串:IamROOT @Value("${quartzpath}") private String quartzpath;//这是配置好的反射path,这里是:com.crm.restapi.schedule.job. @PostMapping(value = "/startjob") public ApiResult startjob(@RequestBody @Valid QuartzParam quartzParam) throws ClassNotFoundException, SchedulerException { // 定义jobdetail Class jobclass = Class.forName(quartzpath + quartzParam.getClassName()); JobDetail job = newJob(jobclass) .withIdentity(quartzParam.getJobName(), quartzParam.getJobGroup()) .build(); // 定义trigger触发器 Trigger trigger = newTrigger() .withIdentity(quartzParam.getTgName(), quartzParam.getTgGroup()) .startNow() .withSchedule(cronSchedule(quartzParam.getTrigger()))//这里是cron表达式 .build(); // Tell quartz to schedule the job using our trigger scheduler.scheduleJob(job, trigger);//定义的JobDetail和trigger注册到scheduler里 return new ApiResult().success(); } @GetMapping("/start") public ApiResult startTask() throws ClassNotFoundException, SchedulerException { scheduler.start(); return new ApiResult().success(); } @GetMapping("/stop") public ApiResult stopTrigger() throws ClassNotFoundException, SchedulerException { scheduler.standby();//这里使用standby()方法,shutdown()方法会把scheduler实例关闭,start也会无法启动 return new ApiResult().success(); } @GetMapping("/list") public ApiResult list() throws ClassNotFoundException, SchedulerException { HashMap map = new HashMap(); Set<JobKey> jobKeySet = scheduler.getJobKeys(GroupMatcher.groupEquals("group1")); map.put("jobNum", jobKeySet.size()); map.put("jobDedail", jobKeySet); map.put("nowJob", scheduler.getCurrentlyExecutingJobs()); return new ApiResult().success(map); } }
QuartzParam.java(这里我用了validation验证)
import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; public class QuartzParam { @Size(min = 1, message = "类(名)不能为空") @NotNull(message = "类(名)不能为空") private String className; @Size(min = 1, message = "任务(名)不能为空") @NotNull(message = "任务(名)不能为空") private String jobName; @Size(min = 1, message = "任务(名)不能为空") @NotNull(message = "任务(名)不能为空") private String jobGroup; @Size(min = 1, message = "触发器(名)不能为空") @NotNull(message = "触发器(名)不能为空") private String tgName; @Size(min = 1, message = "触发器(组)不能为空") @NotNull(message = "触发器(组)不能为空") private String tgGroup; @Size(min = 1, message = "触发器(规则)不能为空") @NotNull(message = "触发器(规则)不能为空") private String trigger; public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getJobName() { return jobName; } public void setJobName(String jobName) { this.jobName = jobName; } public String getJobGroup() { return jobGroup; } public void setJobGroup(String jobGroup) { this.jobGroup = jobGroup; } public String getTgName() { return tgName; } public void setTgName(String tgName) { this.tgName = tgName; } public String getTgGroup() { return tgGroup; } public void setTgGroup(String tgGroup) { this.tgGroup = tgGroup; } public String getTrigger() { return trigger; } public void setTrigger(String trigger) { this.trigger = trigger; } }
Run起来
springboot启动后scheduler实例会自动start
使用postman测试
stop
console
start
console
list
startjob
console
前面步骤,早就已经创建好的数据库表
尾
持久化成功(第一条别纠结,那是我以前用的,第二条数据才是我们测的)
简单快速上手springboot集成quartz的快速教程,简单粗暴的还是需要官方文档;
有问题,欢迎留言;
附上官方文档
org.quartz-scheduler官方文档
quartz学习
Quartz学习——Quartz大致介绍(一)
常见问题
quartz Couldn’t rollback jdbc connection. Communications link failure during rollback().
java.net.SocketException: Broken pipe with Quartz and MySQL and Tomcat (Tomcat Crash)
原文链接:https://blog.csdn.net/qq_20032995/article/details/79141929
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。