Quartz:高階,資料庫儲存
阿新 • • 發佈:2018-11-30
Pom-xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
Quartz排程所需要的依賴 quartz-jobs+c3p0,其他的可在建立SpringBoot專案時勾選jdbc、mysql、quartz、mybatis等
application.properties
spring.datasource.username=root spring.datasource.password=root spring.datasource.url=jdbc:mysql://localhost:3306/cn?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
專案所需要連線的資料庫,cn是MySQL的庫 。com.mysql.cj.jdbc.Driver,新版連線
scheduletrigger
-- ---------------------------- -- Table structure for `scheduletrigger` -- ---------------------------- DROP TABLE IF EXISTS `scheduletrigger`; CREATE TABLE `scheduletrigger` ( `id` int(11) NOT NULL AUTO_INCREMENT, `cron` varchar(255) DEFAULT NULL, `status` varchar(255) DEFAULT NULL, `jobName` varchar(255) DEFAULT NULL, `jobGroup` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of scheduletrigger -- ---------------------------- INSERT INTO `scheduletrigger` VALUES ('1', '*/3 * * * * ?', '1', 'com.hc.quartzboot.quartz.MyJob', 'hc'); INSERT INTO `scheduletrigger` VALUES ('2', '*/10 * * * * ?', '1', 'com.hc.quartzboot.quartz.MyJobs', 'hc');
MySQL中的任務表 ,cron是表示式,jobname是任務的路徑,com.hc.quartzboot.quartz.MyJobs
quartz提供的表官方Quartz--MySQL版的表共11張 表
quartz.properties
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
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.tablePrefix:qrtz_
org.quartz.jobStore.dataSource:qzDS
org.quartz.jobStore.isClustered = true
org.quartz.dataSource.qzDS.driver:com.mysql.cj.jdbc.Driver
org.quartz.dataSource.qzDS.URL:jdbc:mysql://localhost:3306/cn?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
org.quartz.dataSource.qzDS.user:root
org.quartz.dataSource.qzDS.password:root
org.quartz.dataSource.qzDS.maxConnections:10
ScheduleTrigger
package com.hc.quartzboot.model;
public class ScheduleTrigger {
private Integer id;
private String cron;
private String status;
private String jobName;
private String jobGroup;
public ScheduleTrigger(Integer id, String cron, String status, String jobName, String jobGroup) {
this.id = id;
this.cron = cron;
this.status = status;
this.jobName = jobName;
this.jobGroup = jobGroup;
}
public ScheduleTrigger() {
super();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCron() {
return cron;
}
public void setCron(String cron) {
this.cron = cron;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
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;
}
}
ScheduleTriggerMapper
package com.hc.quartzboot.mapper;
import com.hc.quartzboot.model.ScheduleTrigger;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public interface ScheduleTriggerMapper {
@Select(" select * from ScheduleTrigger")
List<ScheduleTrigger> queryAll();
}
MyJob
package com.hc.quartzboot.quartz;
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 MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("任務執行中..." + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date()));
}
}
MyJobFactory
package com.hc.quartzboot.quartz;
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 {
//通過quartz框架中的建立作業的方法建立一個作業物件
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance); //這一步解決不能spring注入bean的問題
return jobInstance;
}
}
MyJobs
package com.hc.quartzboot.quartz;
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 MyJobs implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("任務222執行中..." + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date()));
}
}
QuartzConfiguration
package com.hc.quartzboot.quartz;
import org.quartz.Scheduler;
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 QuartzConfiguration {
@Autowired
private MyJobFactory myJobFactory; //自定義的factory
//獲取工廠bean(獲取任務排程器工廠)
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
try {
schedulerFactoryBean.setQuartzProperties(quartzProperties());
schedulerFactoryBean.setJobFactory(myJobFactory);
return schedulerFactoryBean;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//指定quartz.properties
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
//建立schedule(獲取任務排程器)
@Bean(name = "scheduler")
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}
}
ScheduleTriggerServiceImpl
package com.hc.quartzboot.service.impl;
import com.hc.quartzboot.mapper.ScheduleTriggerMapper;
import com.hc.quartzboot.model.ScheduleTrigger;
import com.hc.quartzboot.service.ScheduleTriggerService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ScheduleTriggerServiceImpl implements ScheduleTriggerService {
@Autowired
private Scheduler scheduler;
@Autowired
private ScheduleTriggerMapper scheduleTriggerMapper;
@Override
//@Scheduled(cron = "0 0 23:00 * * ?") //每天晚上11點呼叫這個方法來更新quartz中的任務
@Scheduled(cron = "*/10 * * * * ?") //每隔30秒執行一次更新quartz中的任務,調小一點好測試
public void refreshTrigger() {
try {
System.out.println("ScheduleTriggerService.refreshTrigger");
//查詢出資料庫中所有的定時任務
List<ScheduleTrigger> jobList = scheduleTriggerMapper.queryAll();
if (jobList != null) {
for (ScheduleTrigger scheduleJob : jobList) {
String status = scheduleJob.getStatus(); //該任務觸發器目前的狀態
TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//說明本條任務還沒有新增到quartz中
if (null == trigger) {
if (status.equals("0")) { //如果是禁用,則不用建立觸發器
continue;
}
JobDetail jobDetail = null;
try {
//建立JobDetail(資料庫中job_name存的任務全路徑,這裡就可以動態的把任務注入到JobDetail中)
jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(scheduleJob.getJobName()))
.withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).build();
////TO//DO
// 可以新增一些額外的引數到任務的上下文中
//獲取當前執行的任務id
// Integer id=scheduleJob.getId();
// //通過任務id獲取引數表中的引數資訊
// List<ScheduleTriggerParam> scheduleTriggerParams=scheduleTriggerParamMapper.findParamByJobId(id);
// JobDataMap jobDataMap=jobDetail.getJobDataMap();
// for (ScheduleTriggerParam param : scheduleTriggerParams) {
// jobDataMap.put(param.getName(),param.getValue());
// }
//表示式排程構建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob
.getCron());
//按新的cronExpression表示式構建一個新的trigger
trigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).withSchedule(scheduleBuilder).build();
//把trigger和jobDetail注入到排程器
scheduler.scheduleJob(jobDetail, trigger);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else { //說明查出來的這條任務,已經設定到quartz中了
// Trigger已存在,先判斷是否需要刪除,如果不需要,再判定是否時間有變化
if (status.equals("0")) { //如果是禁用,從quartz中刪除這條任務
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.deleteJob(jobKey);
continue;
}
String searchCron = scheduleJob.getCron(); //獲取資料庫的
String currentCron = trigger.getCronExpression();
if (!searchCron.equals(currentCron)) { //說明該任務有變化,需要更新quartz中的對應的記錄
//表示式排程構建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(searchCron);
//按新的cronExpression表示式重新構建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
//按新的trigger重新設定job執行
scheduler.rescheduleJob(triggerKey, trigger);
}
}
}
}
} catch (Exception e) {
System.out.println("定時任務每日重新整理觸發器任務異常,在ScheduleTriggerServiceImpl的方法refreshTrigger中,異常資訊:"+e);
throw new RuntimeException(e);
}
}
}
QuartzbootApplication
package com.hc.quartzboot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableScheduling
@EnableTransactionManagement
@MapperScan("com.hc.quartzboot.mapper")
public class QuartzbootApplication {
public static void main(String[] args) {
SpringApplication.run(QuartzbootApplication.class, args);
}
}
啟動即可