项目早期为单体应用,近期因业务量上涨,架构逐渐转为springcloud+分布式集群。原先项目中的定时任务主要采用@Scheduled注解方式实现,并且因历史原因,分布散乱,管理不便。@Scheduled注解的定时任务无法直接应用于集群环境,并且服务重启或异常时,任务容易丢失。Quartz支持对数据的持久化,并且有misfire机制,任务不易丢失,同时支持集群设置,分离出的定时任务可独立为微服务应用,扩展性好。
4.0.0 com.cpdiem.demo quick-quartz 0.0.1-SNAPSHOT jar quick-quartz Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 2.1.1.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-test test junit junit 4.12 test org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-web mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc org.quartz-scheduler quartz 2.3.0 org.quartz-scheduler quartz-jobs 2.3.0 org.springframework spring-context-support com.alibaba druid 1.1.3 hikari-cp hikari-cp 2.6.0 org.springframework.boot spring-boot-starter-data-redis 2.1.1.RELEASE com.alibaba fastjson 1.2.47 org.springframework.boot spring-boot-maven-plugin
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; DROP TABLE IF EXISTS QRTZ_LOCKS; DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS; DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; DROP TABLE IF EXISTS QRTZ_TRIGGERS; DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; DROP TABLE IF EXISTS QRTZ_CALENDARS; CREATE TABLE QRTZ_JOB_DETAILS ( SCHED_NAME VARCHAR(120) NOT NULL, JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, DESCRIPTION VARCHAR(250) NULL, JOB_CLASS_NAME VARCHAR(250) NOT NULL, IS_DURABLE VARCHAR(1) NOT NULL, IS_NONCONCURRENT VARCHAR(1) NOT NULL, IS_UPDATE_DATA VARCHAR(1) NOT NULL, REQUESTS_RECOVERY VARCHAR(1) NOT NULL, JOB_DATA BLOB NULL, PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) ); CREATE TABLE QRTZ_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, DESCRIPTION VARCHAR(250) NULL, NEXT_FIRE_TIME BIGINT(13) NULL, PREV_FIRE_TIME BIGINT(13) NULL, PRIORITY INTEGER NULL, TRIGGER_STATE VARCHAR(16) NOT NULL, TRIGGER_TYPE VARCHAR(8) NOT NULL, START_TIME BIGINT(13) NOT NULL, END_TIME BIGINT(13) NULL, CALENDAR_NAME VARCHAR(200) NULL, MISFIRE_INSTR SMALLINT(2) NULL, JOB_DATA BLOB NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) ); CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, REPEAT_COUNT BIGINT(7) NOT NULL, REPEAT_INTERVAL BIGINT(12) NOT NULL, TIMES_TRIGGERED BIGINT(10) NOT NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE QRTZ_CRON_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, CRON_EXPRESSION VARCHAR(200) NOT NULL, TIME_ZONE_ID VARCHAR(80), PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE QRTZ_SIMPROP_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, STR_PROP_1 VARCHAR(512) NULL, STR_PROP_2 VARCHAR(512) NULL, STR_PROP_3 VARCHAR(512) NULL, INT_PROP_1 INT NULL, INT_PROP_2 INT NULL, LONG_PROP_1 BIGINT NULL, LONG_PROP_2 BIGINT NULL, DEC_PROP_1 NUMERIC(13,4) NULL, DEC_PROP_2 NUMERIC(13,4) NULL, BOOL_PROP_1 VARCHAR(1) NULL, BOOL_PROP_2 VARCHAR(1) NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE QRTZ_BLOB_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, BLOB_DATA BLOB NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE QRTZ_CALENDARS ( SCHED_NAME VARCHAR(120) NOT NULL, CALENDAR_NAME VARCHAR(200) NOT NULL, CALENDAR BLOB NOT NULL, PRIMARY KEY (SCHED_NAME,CALENDAR_NAME) ); CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP) ); CREATE TABLE QRTZ_FIRED_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, ENTRY_ID VARCHAR(95) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, INSTANCE_NAME VARCHAR(200) NOT NULL, FIRED_TIME BIGINT(13) NOT NULL, SCHED_TIME BIGINT(13) NOT NULL, PRIORITY INTEGER NOT NULL, STATE VARCHAR(16) NOT NULL, JOB_NAME VARCHAR(200) NULL, JOB_GROUP VARCHAR(200) NULL, IS_NONCONCURRENT VARCHAR(1) NULL, REQUESTS_RECOVERY VARCHAR(1) NULL, PRIMARY KEY (SCHED_NAME,ENTRY_ID) ); CREATE TABLE QRTZ_SCHEDULER_STATE ( SCHED_NAME VARCHAR(120) NOT NULL, INSTANCE_NAME VARCHAR(200) NOT NULL, LAST_CHECKIN_TIME BIGINT(13) NOT NULL, CHECKIN_INTERVAL BIGINT(13) NOT NULL, PRIMARY KEY (SCHED_NAME,INSTANCE_NAME) ); CREATE TABLE QRTZ_LOCKS ( SCHED_NAME VARCHAR(120) NOT NULL, LOCK_NAME VARCHAR(40) NOT NULL, PRIMARY KEY (SCHED_NAME,LOCK_NAME) ); commit;
server: port: 8088 spring: application: name: quick-quartz datasource: # type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&userSSL=false&serverTimezone=GMT username: root password: root hikari: # minimum-idle: 5 # idle-timeout: 180000 # maximum-pool-size: 10 aoto-commit: true pool-name: MyHikariCP connection-timeout: 30000 jpa: hibernate: #ddl-auto: create ddl-auto: update show-sql: true redis: database: 0 host: localhost port: 6379 password: jedis: pool: max-active: 8 max-wait: -1 max-idle: 8 min-idle: 0 timeout: 5000
org.quartz.scheduler.instanceName = quartzScheduler org.quartz.scheduler.instanceId = AUTO org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.isClustered = true org.quartz.jobStore.useProperties = false org.quartz.jobStore.clusterCheckinInterval = 20000 org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 10 org.quartz.threadPool.threadPriority = 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
quartz.timer1=0/15 * * * * ? quartz.timer2=0 0/2 * * * ? quartz.timer3=0/30 * * * * ?
package com.cpdiem.demo.quickquartz.utils; import com.alibaba.fastjson.util.TypeUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Timestamp; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class PropertiesUtils extends PropertyPlaceholderConfigurer { private static Map
ctxPropertiesMap; /** * 重写processProperties方法 */ @Override protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { super.processProperties(beanFactoryToProcess, props); ctxPropertiesMap = new HashMap (); for (Object key : props.keySet()) { String keyStr = key.toString(); String value = props.getProperty(keyStr); ctxPropertiesMap.put(keyStr, value); } } public static String getProperty(String key) { return TypeUtils.castToString(ctxPropertiesMap.get(key)); } public static Object getObject(String key, Class clazz) { Object obj = getProperty(key); return TypeUtils.castToJavaBean(obj, clazz); } public static Boolean getBoolean(String key) { Object value = getProperty(key); if (value == null) return null; else return TypeUtils.castToBoolean(value); } public static byte[] getBytes(String key) { Object value = getProperty(key); if (value == null) return null; else return TypeUtils.castToBytes(value); } public static boolean getBooleanValue(String key) { Object value = getProperty(key); if (value == null) return false; else return TypeUtils.castToBoolean(value).booleanValue(); } public static Byte getByte(String key) { Object value = getProperty(key); return TypeUtils.castToByte(value); } public static byte getByteValue(String key) { Object value = getProperty(key); if (value == null) return 0; else return TypeUtils.castToByte(value).byteValue(); } public static Short getShort(String key) { Object value = getProperty(key); return TypeUtils.castToShort(value); } public static short getShortValue(String key) { Object value = getProperty(key); if (value == null) return 0; else return TypeUtils.castToShort(value).shortValue(); } public static Integer getInteger(String key) { Object value = getProperty(key); return TypeUtils.castToInt(value); } public static int getIntValue(String key) { Object value = getProperty(key); if (value == null) return 0; else return TypeUtils.castToInt(value).intValue(); } public static Long getLong(String key) { Object value = getProperty(key); return TypeUtils.castToLong(value); } public static long getLongValue(String key) { Object value = getProperty(key); if (value == null) return 0L; else return TypeUtils.castToLong(value).longValue(); } public static Float getFloat(String key) { Object value = getProperty(key); return TypeUtils.castToFloat(value); } public static float getFloatValue(String key) { Object value = getProperty(key); if (value == null) return 0.0F; else return TypeUtils.castToFloat(value).floatValue(); } public static Double getDouble(String key) { Object value = getProperty(key); return TypeUtils.castToDouble(value); } public static double getDoubleValue(String key) { Object value = getProperty(key); if (value == null) return 0.0D; else return TypeUtils.castToDouble(value).doubleValue(); } public static BigDecimal getBigDecimal(String key) { Object value = getProperty(key); return TypeUtils.castToBigDecimal(value); } public static BigInteger getBigInteger(String key) { Object value = getProperty(key); return TypeUtils.castToBigInteger(value); } public static String getString(String key) { Object value = getProperty(key); if (value == null) return null; else return value.toString(); } public static Date getDate(String key) { Object value = getProperty(key); return TypeUtils.castToDate(value); } public static java.sql.Date getSqlDate(String key) { Object value = getProperty(key); return TypeUtils.castToSqlDate(value); } public static Timestamp getTimestamp(String key) { Object value = getProperty(key); return TypeUtils.castToTimestamp(value); } }
package com.cpdiem.demo.quickquartz.utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.Map; import java.util.Set; @Component public class RedisUtils { @Autowired private RedisTemplate redisTemplate; /** * 根据key获取Set中的所有值 * @param key 键 * @return */ public Set
package com.cpdiem.demo.quickquartz.Jobs; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Date; /** * 定时调度任务Job1. * * */ @Component public class Job1 extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); System.out.println("@@@@@@@@@@@@ "+(new SimpleDateFormat("yyyy-mm-dd HH:mm:ss.SSSSSS")).format(new Date())+" @@@@@@@@@@@"); System.out.println("@@@@@@@@@@@@@@@@@@@@@@@ Job1 @@@@@@@@@@@@@@@@@@@@@@"); System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); System.out.println(); } }
package com.cpdiem.demo.quickquartz.Jobs; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.quartz.QuartzJobBean; import java.text.SimpleDateFormat; import java.util.Date; /** * 定时调度任务Job2. * */ public class Job2 extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("=================================================================="); System.out.println("=========== "+(new SimpleDateFormat("yyyy-mm-dd HH:mm:ss.SSSSSS")).format(new Date())+" ============"); System.out.println("======================= Job2 ======================"); System.out.println("=================================================================="); System.out.println(); } }
package com.cpdiem.demo.quickquartz.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; public class RedisConfig { @Bean @SuppressWarnings("all") public RedisTemplate
redisTemplate(RedisConnectionFactory factory) { RedisTemplate template = new RedisTemplate (); template.setConnectionFactory(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
package com.cpdiem.demo.quickquartz.config; import com.cpdiem.demo.quickquartz.Jobs.Job1; import com.cpdiem.demo.quickquartz.Jobs.Job2; import com.cpdiem.demo.quickquartz.utils.PropertiesUtils; import com.cpdiem.demo.quickquartz.utils.RedisUtils; import org.quartz.JobDetail; import org.quartz.Trigger; import org.quartz.spi.JobFactory; import org.quartz.spi.TriggerFiredBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.JobDetailFactoryBean; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.scheduling.quartz.SpringBeanJobFactory; import javax.sql.DataSource; import java.io.IOException; import java.util.Properties; /** * Quartz调度配置类。 * * */ @Configuration public class QuartzSchedulerConfig { @Autowired private DataSource dataSource; @Autowired private RedisUtils redisUtils; private static final Logger Logger = LoggerFactory.getLogger(QuartzSchedulerConfig.class); private static final String QUARTZ_PROPERTIES_NAME = "/config/quartz.properties"; @Bean public JobFactory jobFactory(ApplicationContext applicationContext) { AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } @Bean public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, Trigger[] triggers, JobDetail[] jobDetails) { SchedulerFactoryBean factoryBean = new SchedulerFactoryBean(); try { factoryBean.setQuartzProperties(quartzProperties()); factoryBean.setDataSource(dataSource); factoryBean.setJobFactory(jobFactory); factoryBean.setTriggers(triggers); factoryBean.setJobDetails(jobDetails); factoryBean.setOverwriteExistingJobs(true); factoryBean.setStartupDelay(10); factoryBean.setWaitForJobsToCompleteOnShutdown(true); } catch (Exception e) { Logger.error("加载 {} 配置文件失败.", QUARTZ_PROPERTIES_NAME, e); throw new RuntimeException("加载配置文件失败", e); } tempSetTriggers(triggers); return factoryBean; } void tempSetTriggers(Trigger[] triggers){ if(triggers.length>0){ for(Trigger trigger : triggers){ redisUtils.sSet("Triggers",trigger.getKey().getName()); } } } public Properties quartzProperties() throws IOException { PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_PROPERTIES_NAME)); propertiesFactoryBean.afterPropertiesSet(); return propertiesFactoryBean.getObject(); } class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; @Override public void setApplicationContext(final ApplicationContext context) { beanFactory = context.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } } @Bean(name = "job1Trigger") public CronTriggerFactoryBean job1Trigger(@Qualifier("job1Detail") JobDetail jobDetail) { CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean(); cronTriggerFactoryBean.setJobDetail(jobDetail); cronTriggerFactoryBean.setCronExpression(PropertiesUtils.getProperty("quartz.timer1")); cronTriggerFactoryBean.setGroup("first"); cronTriggerFactoryBean.setName("job1Trigger"); return cronTriggerFactoryBean; } @Bean(name = "job1Detail") public JobDetailFactoryBean job1Detail() { JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean(); jobDetailFactoryBean.setJobClass(Job1.class); jobDetailFactoryBean.setDurability(true); return jobDetailFactoryBean; } @Bean(name = "job2Trigger") public CronTriggerFactoryBean job2Trigger(@Qualifier("job2Detail") JobDetail jobDetail) { CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean(); cronTriggerFactoryBean.setJobDetail(jobDetail); cronTriggerFactoryBean.setCronExpression(PropertiesUtils.getProperty("quartz.timer2")); return cronTriggerFactoryBean; } @Bean(name = "job2Detail") public JobDetailFactoryBean job2Detail() { JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean(); jobDetailFactoryBean.setJobClass(Job2.class); jobDetailFactoryBean.setDurability(true); return jobDetailFactoryBean; } // @Bean(name = "job3Trigger") // public CronTriggerFactoryBean job3Trigger(@Qualifier("job1Detail") JobDetail jobDetail) { // CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean(); // cronTriggerFactoryBean.setJobDetail(jobDetail); // cronTriggerFactoryBean.setCronExpression(PropertiesUtils.getProperty("quartz.timer3")); // return cronTriggerFactoryBean; // } }
任务辅助类(quick-quartz\src\main\java\com\cpdiem\demo\quickquartz\service\JobTaskService.java)
package com.cpdiem.demo.quickquartz.service; import com.cpdiem.demo.quickquartz.utils.RedisUtils; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.impl.matchers.GroupMatcher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.HashSet; import java.util.List; import java.util.Set; @Component public class JobTaskService { @Autowired private SchedulerFactoryBean schedulerFactoryBean; @Autowired private RedisUtils redisUtils; @PostConstruct private void updateJobTaskBeforeStarting(){ Set
hashSet = new HashSet (); Set set = redisUtils.sGet("Triggers"); if(set!=null && set.size()>0){ for(Object obj : set){ hashSet.add((String)obj); } } Scheduler scheduler = schedulerFactoryBean.getScheduler(); Set jobKeySet = null; try { jobKeySet = scheduler.getJobKeys(GroupMatcher. anyGroup()); if(jobKeySet != null && jobKeySet.size()>0) { for (JobKey jk : jobKeySet) { List triggers = (List ) scheduler.getTriggersOfJob(jk); if (triggers != null && triggers.size() > 0) { for (Trigger trigger : triggers) { if(!hashSet.contains(trigger.getKey().getName())){ scheduler.unscheduleJob(trigger.getKey()); } } } } } redisUtils.setRemove("Triggers",hashSet.toArray()); } catch (SchedulerException e) { e.printStackTrace(); } } }
启动类
@SpringBootApplication public class QuickQuartzApplication { public static void main(String[] args) { ConfigurableApplicationContext configurableApplicationContext =SpringApplication.run(QuickQuartzApplication.class, args); configurableApplicationContext.getEnvironment(); } @Bean public PropertiesUtils PropertiesUtils(){ PropertiesUtils propertiesUtils = new PropertiesUtils(); propertiesUtils.setLocation(new ClassPathResource("/config/timers.properties")); return propertiesUtils; } }
factoryBean.setOverwriteExistingJobs(true);
该参数默认值为false。当应用启动时,quartz不会更新相关数据库表中的数据(如cron表达式,任务下次执行时间等等),调度器将根据数据库原有数据信息执行任务。
该参数设为true时,数据库数据会被重新设置。如果应用重启、宕机期间有任务错过,将不触发misfire。
quartz在创建完scheduler时,会同时维护数据库及本次应用创建的任务,也就是说quartz只会进行新增、更新操作,不会执行删除操作。因此,对于不再使用的触发器,需自行手动删除(任务辅助类JobTaskService存在的意义,当然它可以做得更多)。
factoryBean.setStartupDelay(10);
设置调度中心在应用启动后n秒后开始运行。
factoryBean.setWaitForJobsToCompleteOnShutdown(true);
该参数用于设置当服务正常关闭时,会等所有任务执行完毕后再行关闭。但仍存在不正常关闭的bug。