SpringBoot 1.5.x 集成 Quartz 任务调度框架

Posted 1994july

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot 1.5.x 集成 Quartz 任务调度框架相关的知识,希望对你有一定的参考价值。

Quartz 有分 内存方式 和 数据库方式

内存方式任务信息保存在内存中, 停机会丢失, 需手动重新执行, 数据库方式: 任务信息保存在数据库中, 重点是支持集群.

内存方式 RAMJobStore 和 数据库方式 JobStoreTX, RAMJobStore 适合单机, 不支持集群,  JobStoreTX 支持集群.

下面介绍的就是 JobStoreTX 数据库方式.

1. 添加主要的相关依赖, 其他依赖这里就不说了

<dependency>
	<groupId>org.quartz-scheduler</groupId>
	<artifactId>quartz</artifactId>
	<version>2.3.0</version>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context-support</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-tx</artifactId>
</dependency>

2. quartz 的数据库表目前有 11 个, 可以下载官方包, 在官方包中可以找到建表语句, 对应不同的数据库有相应的sql语句. 

技术图片

配置文件 quartz.properties 

org.quartz.scheduler.instanceName=DefaultQuartzScheduler
org.quartz.scheduler.instanceid=AUTO
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=20
org.quartz.threadPool.threadPriority=5
org.quartz.jobStore.misfireThreshold=2000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=20000
org.quartz.dataSource.myDS.driver=org.mariadb.jdbc.Driver
org.quartz.dataSource.myDS.URL=jdbc:mariadb://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
#org.quartz.dataSource.myDS.driver=com.mysql.jdbc.Driver
#org.quartz.dataSource.myDS.URL=jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
org.quartz.dataSource.myDS.user=root 
org.quartz.dataSource.myDS.password=root
org.quartz.dataSource.myDS.maxConnections=5 
org.quartz.dataSource.myDS.validationQuery=select 0 from dual

3. JobFactory 

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

@Configuration
public class JobFactory extends SpringBeanJobFactory {

	@Autowired
	private AutowireCapableBeanFactory autowireCapableBeanFactory;
	
	@Override
	protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
		Object createJobInstance = super.createJobInstance(bundle);
		autowireCapableBeanFactory.autowireBean(createJobInstance);
		return createJobInstance;
	}
}

4. QuartzConfig 

import java.io.IOException;
import java.util.Properties;

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;

@Configuration
public class QuartzConfig {
	
	@Autowired
	private JobFactory jobFactory;
	
//	@Autowired
//	private DataSource dataSource;    // 如果使用application.properties中的数据源可以用这种方式
	
	@Bean
	public SchedulerFactoryBean myScheduler() throws IOException {
		SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
//		schedulerFactoryBean.setDataSource(dataSource);                  // 使用 application.properties 中的数据源
		schedulerFactoryBean.setOverwriteExistingJobs(true);
		schedulerFactoryBean.setJobFactory(jobFactory);
		schedulerFactoryBean.setQuartzProperties(quartzProperties());    // 使用 quartz.properties 中的数据源
		schedulerFactoryBean.setSchedulerName("myScheduler");
		schedulerFactoryBean.setStartupDelay(2);// 延迟两秒启动
		schedulerFactoryBean.setAutoStartup(true);
		return schedulerFactoryBean;
	}
	
	@Bean
	public SchedulerFactoryBean myScheduler2() throws IOException {
		SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
//		schedulerFactoryBean.setDataSource(dataSource);				   // 使用 application.properties 中的数据源
		schedulerFactoryBean.setOverwriteExistingJobs(true);
		schedulerFactoryBean.setJobFactory(jobFactory);
		schedulerFactoryBean.setQuartzProperties(quartzProperties());  // 使用 quartz.properties 中的数据源
		schedulerFactoryBean.setSchedulerName("myScheduler2");
		schedulerFactoryBean.setStartupDelay(2);// 延迟两秒启动
		schedulerFactoryBean.setAutoStartup(true);
		return schedulerFactoryBean;
	}
	
	private Properties quartzProperties() throws IOException {
		PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
		propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
		propertiesFactoryBean.afterPropertiesSet();
		Properties properties = propertiesFactoryBean.getObject();
		return properties;
	}
}

5. JobController

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.codingos.springboot.model.JobInfo;

@RestController
public class JobController {
	
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	private Scheduler myScheduler;   // 这个注入应该和 config 类中 @Bean 的方法名相同
	@Autowired
	private Scheduler myScheduler2;  // 这个注入应该和 config 类中 @Bean 的方法名相同
	
	
	/**
	 * 创建Job
	 */
	@PostMapping("/createJob")
	public void createJob(@RequestBody JobInfo jobInfo) {
		Scheduler scheduler = getScheduler(jobInfo.getSchedulerName());
		
		Class<? extends Job> jobClass = null;
		try {
			jobClass = (Class<? extends Job>) Class.forName(jobInfo.getJobClassName());
		} catch (ClassNotFoundException e) {
			logger.error("create Job " + jobInfo.getJobName() + " error: " + e.getMessage(), e);
		}
		JobKey jobKey = new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
		JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobKey).storeDurably().build();
		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCron());
		TriggerKey triggerKey = new TriggerKey(jobInfo.getTriggerName(), jobInfo.getTriggerGroup());
		CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).forJob(jobDetail).withSchedule(scheduleBuilder).build();
		try {
			scheduler.scheduleJob(jobDetail, cronTrigger);
			scheduler.pauseJob(jobKey);   // 如果此处不暂停, 就会直接运行job
		} catch (SchedulerException e) {
			logger.error("create Job " + jobInfo.getJobName() + " error: " + e.getMessage(), e);
		}
	}
	
	@PostMapping("/jobStrat")
	public void jobStrat(@RequestBody JobInfo jobInfo) {
		Scheduler scheduler = getScheduler(jobInfo.getSchedulerName());
		JobKey jobKey = new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
		try {
			scheduler.resumeJob(jobKey);  // 恢复执行job
		} catch (SchedulerException e) {
			logger.error("Job " + jobInfo.getJobName() + " start error: " + e.getMessage(), e);
		}
	}
	
	@PostMapping("/jobStop")
	public void jobStop(@RequestBody JobInfo jobInfo) {
		Scheduler scheduler = getScheduler(jobInfo.getSchedulerName());
		JobKey jobKey = new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
		try {
			scheduler.pauseJob(jobKey);  // 暂停运行job
		} catch (SchedulerException e) {
			logger.error("Job " + jobInfo.getJobName() + " stop error: " + e.getMessage(), e);
		}
		
	}
	
	@PostMapping("/jobEdit")
	public void jobEdit(@RequestBody JobInfo jobInfo) {
		Scheduler scheduler = getScheduler(jobInfo.getSchedulerName());
		JobKey jobKey = new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
		try {
			TriggerKey triggerKey = new TriggerKey(jobInfo.getTriggerName(), jobInfo.getTriggerGroup());
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCron());
			CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).forJob(jobKey).withSchedule(scheduleBuilder).build();
			scheduler.rescheduleJob(triggerKey, cronTrigger);  // 更新对应的 trigger
		} catch (SchedulerException e) {
			logger.error("Job " + jobInfo.getJobName() + " edit error: " + e.getMessage(), e);
		}
	}
	
	@PostMapping("/jobDelete")
	public void jobDelete(@RequestBody JobInfo jobInfo) {
		Scheduler scheduler = getScheduler(jobInfo.getSchedulerName());
		JobKey jobKey = new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
		try {
			scheduler.deleteJob(jobKey);  // 删除job和对应的trigger 
		} catch (SchedulerException e) {
			logger.error("Job " + jobInfo.getJobName() + " stop error: " + e.getMessage(), e);
		}
	}
	
	private Scheduler getScheduler(String schedulerName) {
		Scheduler scheduler = null;
		switch (schedulerName) {
		case "myScheduler":
			scheduler = myScheduler;
			break;
		case "myScheduler2":
			scheduler = myScheduler2;
			break;
		default:
			break;
		}
		return scheduler;
	}
}

6. Job 类

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import com.codingos.springboot.service.Job1Service;

public class Job1 extends QuartzJobBean {
	
	@Autowired
	private Job1Service job1Service;

	@Override
	protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
		job1Service.service1();
	}
}

7. JobInfo 类

public class JobInfo {

	private String jobName;
	private String jobGroup;
	private String jobClassName;
	private String triggerName;
	private String triggerGroup;
	private String schedulerName;
	private String prevExecuteTime;
	private String nextExecuteTime;
	private String cron;
	private String triggerState;
	
	public JobInfo() {
	}

	public String getJobName() {
		return jobName;
	}

	public void setJobName(String jobName) {
		this.jobName = jobName;
	}

	public String getCron() {
		return cron;
	}

	public void setCron(String cron) {
		this.cron = cron;
	}

	public String getTriggerState() {
		return triggerState;
	}

	public void setTriggerState(String triggerState) {
		this.triggerState = triggerState;
	}

	public String getJobGroup() {
		return jobGroup;
	}

	public void setJobGroup(String jobGroup) {
		this.jobGroup = jobGroup;
	}

	public String getTriggerName() {
		return triggerName;
	}

	public void setTriggerName(String triggerName) {
		this.triggerName = triggerName;
	}

	public String getTriggerGroup() {
		return triggerGroup;
	}

	public void setTriggerGroup(String triggerGroup) {
		this.triggerGroup = triggerGroup;
	}

	public String getPrevExecuteTime() {
		return prevExecuteTime;
	}

	public void setPrevExecuteTime(String prevExecuteTime) {
		this.prevExecuteTime = prevExecuteTime;
	}

	public String getNextExecuteTime() {
		return nextExecuteTime;
	}

	public void setNextExecuteTime(String nextExecuteTime) {
		this.nextExecuteTime = nextExecuteTime;
	}

	public String getJobClassName() {
		return jobClassName;
	}

	public void setJobClassName(String jobClassName) {
		this.jobClassName = jobClassName;
	}

	public String getSchedulerName() {
		return schedulerName;
	}

	public void setSchedulerName(String schedulerName) {
		this.schedulerName = schedulerName;
	}
}

 

 

最后, 说一下, 如果是 SpringBoot 2.x 集成 Quartz 框架, 添加依赖就非常方便了

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

 来源:湖北网站优化

以上是关于SpringBoot 1.5.x 集成 Quartz 任务调度框架的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot Quartz 动态配置,持久化

Quart,聊天服务器示例

SpringBoot 1.5.x和2.0.x区别

springboot 1.5.X junit测试

python 通过 asyncio 同时使用 flask (quart)与 websocket

Quart 学习