quartz使用及原理解析
quartz简介
Quartz是OpenSymphony
开源组织在Job scheduling
领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer
。但是相较于Timer, Quartz增加了很多功能:
-
持久性作业 - 就是保持调度定时的状态;
-
作业管理 - 对调度作业进行有效的管理;
官方文档:
-
http://www.quartz-scheduler.org/documentation/
-
http://www.quartz-scheduler.org/api/2.3.0/index.html
quartz的使用
非Spring环境
引入
<!-- 核心包 -->
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version>
</dependency>
<!-- 工具包 -->
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId><version>2.3.0</version>
</dependency>
编码
1、新建一个任务,实现 org.quartz.Job
接口:
public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("任务被执行了。。。");}
}
2、创建调度器、jobDetail 实例、trigger 实例、执行
public static void main(String[] args) throws Exception {// 1.创建调度器 SchedulerSchedulerFactory factory = new StdSchedulerFactory();Scheduler scheduler = factory.getScheduler();// 2.创建JobDetail实例,并与MyJob类绑定(Job执行内容)JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").build();// 3.构建Trigger实例,每隔30s执行一次Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow()//设置跑在哪个scheduler上,频率是什么.withSchedule(simpleSchedule().withIntervalInSeconds(30).repeatForever()).build();// 4.执行,开启调度器scheduler.scheduleJob(job, trigger);System.out.println(System.currentTimeMillis());scheduler.start();//主线程睡眠1分钟,然后关闭调度器TimeUnit.MINUTES.sleep(1);scheduler.shutdown();System.out.println(System.currentTimeMillis());
}
与Spring boot集成
引入
<!-- Quartz 任务调度 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
默认在spring-boot-autoconfigure
jar包中已自动配置。包 org.springframework.boot.autoconfigure.quartz
。
编码
同上。
其他说明
Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行, 如果定时任执行太长,会长时间占用资源,导致其它任务堵塞。
@DisallowConcurrentExecution
禁止并发执行多个相同定义的JobDetail, 这个注解是加在Job类上的, 但意思并不是不能同时执行多个Job, 而是不能并发执行同一个Job Definition
(由JobDetail定义), 但是可以同时执行多个不同的JobDetail。
@PersistJobDataAfterExecution
同样, 也是加在Job上。表示当正常执行完Job后, JobDataMap中的数据应该被改动, 以被下一次调用时用。
当使用 @PersistJobDataAfterExecution
注解时, 为了避免并发时, 存储数据造成混乱, 强烈建议把 @DisallowConcurrentExecution
注解也加上。
阻止特定时间运行
//2014-8-15这一天不执行任何任务
Calendar c = new GregorianCalendar(2014, 7, 15);
cal.setDayExcluded(c, true);
scheduler.addCalendar("exclude", cal, false, false);
核心类介绍
Quartz 的核心类有以下三部分:
- 任务 Job : 需要实现的任务类,实现
execute()
方法,执行后完成任务。 - 触发器 Trigger : 包括
SimpleTrigger
和CronTrigger
。 - 调度器 Scheduler : 任务调度器,负责基于
Trigger
触发器,来执行 Job任务
JobDetail
JobDetail 的作用是绑定 Job,是一个任务实例,它为 Job 添加了许多扩展参数。
每次Scheduler
调度执行一个Job的时候,首先会拿到对应的Job的类,然后创建该Job实例,再去执行Job中的execute()
的内容,任务执行结束后,关联的Job对象实例会被释放,且会被JVM GC清除。
JobDetail 就是一个Job实例的包装类。Sheduler每次执行,都会根据新的Job实例,这样就可以 规避并发访问 的问题。
JobExecutionContext
- 当
Scheduler
调用一个 job,就会将JobExecutionContext
传递给 Job 的execute()
方法; - Job 能通过
JobExecutionContext
对象访问到 Quartz 运行时候的环境以及 Job 本身的明细数据。
JobDataMap
有状态的 job 可以理解为多次 job调用期间可以持有一些状态信息,这些状态信息存储在 JobDataMap
中。
而默认的无状态 job,每次调用时都会创建一个新的 JobDataMap
。
让Job支持有状态,则需要在Job类上加注解
@PersistJobDataAfterExecution
Trigger
Trigger
可以设置任务的开始结束时间, Scheduler
会根据参数进行触发。
Calendar
一个Trigger可以和多个Calendar关联,以便排除或包含某些时间点。例如:每周星期一早上10:00执行任务,但是如果碰到法定的节日,则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。
public interface Calendar extends java.io.Serializable, java.lang.Cloneable {int MONTH = 0;void setBaseCalendar(Calendar baseCalendar);Calendar getBaseCalendar();boolean isTimeIncluded(long timeStamp);//获取给定时间之后的下一个include 时间。long getNextIncludedTime(long timeStamp);String getDescription();void setDescription(String description);Object clone();
}
Calendar 名称 | 用法 | 精度 |
---|---|---|
BaseCalendar | 为高级的 Calendar 实现了基本的功能,实现了 org.quartz.Calendar 接口 | |
AnnualCalendar | 指定年中一天或多天。忽略年份。 | 天 |
CronCalendar | 指定CronExpression表达的时间集合。 | 秒 |
DailyCalendar | 每个DailyCalendar仅允许指定单个时间范围,并且该时间范围可能不会跨越每日边界(即,您不能指定从上午8点至凌晨5点的时间范围)。 如果属性invertTimeRange为false(默认),则时间范围定义触发器不允许触发的时间范围。 如果invertTimeRange为true,则时间范围被反转 - 也就是排除在定义的时间范围之外的所有时间。 | 毫秒 |
HolidayCalendar | 从 Trigger 中排除/包含节假日 | 天 |
MonthlyCalendar | 排除/包含月份中的指定数天 | 天 |
WeeklyCalendar | 排除/包含星期中的任意周几 | 天 |
源码解析
配置
QuartzAutoConfiguration
quartz在Spring boot 中 通过 在spring-boot-autoconfigure
jar中的包 org.springframework.boot.autoconfigure.quartz
下的 QuartzAutoConfiguration
类进行配置。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class, PlatformTransactionManager.class })
@EnableConfigurationProperties(QuartzProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,LiquibaseAutoConfiguration.class, FlywayAutoConfiguration.class })
public class QuartzAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic SchedulerFactoryBean quartzScheduler(QuartzProperties properties,ObjectProvider<SchedulerFactoryBeanCustomizer> customizers, ObjectProvider<JobDetail> jobDetails,Map<String, Calendar> calendars, ObjectProvider<Trigger> triggers, ApplicationContext applicationContext) {SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();jobFactory.setApplicationContext(applicationContext);schedulerFactoryBean.setJobFactory(jobFactory);if (properties.getSchedulerName() != null) {schedulerFactoryBean.setSchedulerName(properties.getSchedulerName());}schedulerFactoryBean.setAutoStartup(properties.isAutoStartup());schedulerFactoryBean.setStartupDelay((int) properties.getStartupDelay().getSeconds());schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(properties.isWaitForJobsToCompleteOnShutdown());schedulerFactoryBean.setOverwriteExistingJobs(properties.isOverwriteExistingJobs());if (!properties.getProperties().isEmpty()) {schedulerFactoryBean.setQuartzProperties(asProperties(properties.getProperties()));}schedulerFactoryBean.setJobDetails(jobDetails.orderedStream().toArray(JobDetail[]::new));schedulerFactoryBean.setCalendars(calendars);schedulerFactoryBean.setTriggers(triggers.orderedStream().toArray(Trigger[]::new));customizers.orderedStream().forEach((customizer) -> customizer.customize(schedulerFactoryBean));return schedulerFactoryBean;}private Properties asProperties(Map<String, String> source) {Properties properties = new Properties();properties.putAll(source);return properties;}@Configuration(proxyBeanMethods = false)@ConditionalOnSingleCandidate(DataSource.class)@ConditionalOnProperty(prefix = "spring.quartz", name = "job-store-type", havingValue = "jdbc")protected static class JdbcStoreTypeConfiguration {@Bean@Order(0)public SchedulerFactoryBeanCustomizer dataSourceCustomizer(QuartzProperties properties, DataSource dataSource,@QuartzDataSource ObjectProvider<DataSource> quartzDataSource,ObjectProvider<PlatformTransactionManager> transactionManager) {return (schedulerFactoryBean) -> {DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);schedulerFactoryBean.setDataSource(dataSourceToUse);PlatformTransactionManager txManager = transactionManager.getIfUnique();if (txManager != null) {schedulerFactoryBean.setTransactionManager(txManager);}};}private DataSource getDataSource(DataSource dataSource, ObjectProvider<DataSource> quartzDataSource) {DataSource dataSourceIfAvailable = quartzDataSource.getIfAvailable();return (dataSourceIfAvailable != null) ? dataSourceIfAvailable : dataSource;}@Bean@ConditionalOnMissingBeanpublic QuartzDataSourceInitializer quartzDataSourceInitializer(DataSource dataSource,@QuartzDataSource ObjectProvider<DataSource> quartzDataSource, ResourceLoader resourceLoader,QuartzProperties properties) {DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);return new QuartzDataSourceInitializer(dataSourceToUse, resourceLoader, properties);}/*** Additional configuration to ensure that {@link SchedulerFactoryBean} and* {@link Scheduler} beans depend on any beans that perform data source* initialization.*/@Configuration(proxyBeanMethods = false)static class QuartzSchedulerDependencyConfiguration {@Beanstatic SchedulerDependsOnBeanFactoryPostProcessor quartzSchedulerDataSourceInitializerDependsOnBeanFactoryPostProcessor() {return new SchedulerDependsOnBeanFactoryPostProcessor(QuartzDataSourceInitializer.class);}@Bean@ConditionalOnBean(FlywayMigrationInitializer.class)static SchedulerDependsOnBeanFactoryPostProcessor quartzSchedulerFlywayDependsOnBeanFactoryPostProcessor() {return new SchedulerDependsOnBeanFactoryPostProcessor(FlywayMigrationInitializer.class);}@Configuration(proxyBeanMethods = false)@ConditionalOnClass(SpringLiquibase.class)static class LiquibaseQuartzSchedulerDependencyConfiguration {@Bean@ConditionalOnBean(SpringLiquibase.class)static SchedulerDependsOnBeanFactoryPostProcessor quartzSchedulerLiquibaseDependsOnBeanFactoryPostProcessor() {return new SchedulerDependsOnBeanFactoryPostProcessor(SpringLiquibase.class);}}}}/*** {@link AbstractDependsOnBeanFactoryPostProcessor} for Quartz {@link Scheduler} and* {@link SchedulerFactoryBean}.*/private static class SchedulerDependsOnBeanFactoryPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {SchedulerDependsOnBeanFactoryPostProcessor(Class<?>... dependencyTypes) {super(Scheduler.class, SchedulerFactoryBean.class, dependencyTypes);}}}
在创建 SchedulerFactoryBean
时 ,会把设置JobDetails,Triggers。
SchedulerFactoryBean
可以通过 SchedulerFactoryBeanCustomizer
来设置属性。
@FunctionalInterface
public interface SchedulerFactoryBeanCustomizer {/*** Customize the {@link SchedulerFactoryBean}.* @param schedulerFactoryBean the scheduler to customize*/void customize(SchedulerFactoryBean schedulerFactoryBean);}
QuartzProperties
quartz 的 配置通过 spring.quartz
参数 配置。
quartz.properties里边的配置,都可以放到application.yml里的
spring. quartz.properties
下边
spring:quartz:properties:org:quartz:threadPool:threadCount: 10threadPriority: 5jobStore:misfireThreshold: 50000
@ConfigurationProperties("spring.quartz")
public class QuartzProperties {/*** Quartz job store type.*/private JobStoreType jobStoreType = JobStoreType.MEMORY;private String schedulerName;private boolean autoStartup = true;private Duration startupDelay = Duration.ofSeconds(0);private boolean waitForJobsToCompleteOnShutdown = false;private boolean overwriteExistingJobs = false;/*** spring. quartz.properties*/private final Map<String, String> properties = new HashMap<>();private final Jdbc jdbc = new Jdbc();}
加载配置过程
1、获取spring 配置
//QuartzAutoConfiguration.QuartzAutoConfigurationif (!properties.getProperties().isEmpty()) {schedulerFactoryBean.setQuartzProperties(asProperties(properties.getProperties()));}
2、合并一些配置,并初始化
//SchedulerFactoryBean
private void initSchedulerFactory(StdSchedulerFactory schedulerFactory) throws SchedulerException, IOException {Properties mergedProps = new Properties();if (this.resourceLoader != null) {mergedProps.setProperty(StdSchedulerFactory.PROP_SCHED_CLASS_LOAD_HELPER_CLASS,ResourceLoaderClassLoadHelper.class.getName());}if (this.taskExecutor != null) {mergedProps.setProperty(StdSchedulerFactory.PROP_THREAD_POOL_CLASS,LocalTaskExecutorThreadPool.class.getName());}else {// Set necessary default properties here, as Quartz will not apply// its default configuration when explicitly given properties.mergedProps.setProperty(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, SimpleThreadPool.class.getName());mergedProps.setProperty(PROP_THREAD_COUNT, Integer.toString(DEFAULT_THREAD_COUNT));}// 加载配置文件中的配置 if (this.configLocation != null) {if (logger.isDebugEnabled()) {logger.debug("Loading Quartz config from [" + this.configLocation + "]");}PropertiesLoaderUtils.fillProperties(mergedProps, this.configLocation);}//合并 配置CollectionUtils.mergePropertiesIntoMap(this.quartzProperties, mergedProps);if (this.dataSource != null) {mergedProps.setProperty(StdSchedulerFactory.PROP_JOB_STORE_CLASS, LocalDataSourceJobStore.class.getName());}// Determine scheduler name across local settings and Quartz properties...if (this.schedulerName != null) {mergedProps.setProperty(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME, this.schedulerName);}else {String nameProp = mergedProps.getProperty(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME);if (nameProp != null) {this.schedulerName = nameProp;}else if (this.beanName != null) {mergedProps.setProperty(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME, this.beanName);this.schedulerName = this.beanName;}}//初始化schedulerFactory.initialize(mergedProps);}
调度
quartz使用 SchedulerFactory
来实例化一个 调度器 。
SchedulerFactory
public interface SchedulerFactory {Scheduler getScheduler() throws SchedulerException;Scheduler getScheduler(String schedName) throws SchedulerException;Collection<Scheduler> getAllSchedulers() throws SchedulerException;}
quartz为SchedulerFactory
实现了2个实现类。
- StdSchedulerFactory:创建scheduler的标准工厂。
- DirectSchedulerFactory :直接创建scheduler的工厂,简单的单例实现,提供一些便捷方式。没有复杂的配置。
StdSchedulerFactory
创建scheduler的标准工厂。
通常是通过quartz.properties属性配置文件(默认情况下均使用该文件)结合StdSchedulerFactory 来使用Quartz的。StdSchedulerFactory 会加载属性配置文件并实例化一个Scheduler
DirectSchedulerFactory
Scheduler
Scheduler 维护了一个 JobDetails 和 Triggers 的注册表。
一旦在 Scheduler 注册过了,当定时任务触发时间一到,调度程序就会负责执行预先定义的 Job调度程序创建之后,处于 “ 待机 ” 状态,必须调用 scheduler 的 start() 方法启用调度程序可以使用 shutdown() 方法关闭调度程序,使用 isShutdown() 方法判断该调度程序是否已经处于关闭状态
通过 Scheduler.scheduleJob(…) 方法将任务纳入调度程序中,当任务触发时间到了的时候,该任务将被
执行
quartz的实现类如下:

public interface Scheduler {//默认 Group:DEFAULT,用于Job,Trigger。String DEFAULT_GROUP = Key.DEFAULT_GROUP;String DEFAULT_RECOVERY_GROUP = "RECOVERING_JOBS";/** 用于Trigger */String DEFAULT_FAIL_OVER_GROUP = "FAILED_OVER_JOBS";String FAILED_JOB_ORIGINAL_TRIGGER_NAME = "QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME";String FAILED_JOB_ORIGINAL_TRIGGER_GROUP = "QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP";String FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS = "QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING";String FAILED_JOB_ORIGINAL_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS = "QRTZ_FAILED_JOB_ORIG_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS_AS_STRING";String getSchedulerName() throws SchedulerException;String getSchedulerInstanceId() throws SchedulerException;SchedulerContext getContext() throws SchedulerException;/**Scheduler 创建时的状态为:stand-by。不能执行触发器。必须启动之后。*/void start() throws SchedulerException;/**延迟多久启动**/void startDelayed(int seconds) throws SchedulerException; boolean isStarted() throws SchedulerException;/*** 切回 stand-by 模式。*/void standby() throws SchedulerException;boolean isInStandbyMode() throws SchedulerException;/*** 关闭 scheduler。不能再重新启动了。* 等同 shutdown(false)*/void shutdown() throws SchedulerException;/*** @param waitForJobsToComplete,为true,表示一直阻塞 所有任务执行完成。*/void shutdown(boolean waitForJobsToComplete)throws SchedulerException;boolean isShutdown() throws SchedulerException;SchedulerMetaData getMetaData() throws SchedulerException;/** 获取所有正在执行的任务*/List<JobExecutionContext> getCurrentlyExecutingJobs() throws SchedulerException;void setJobFactory(JobFactory factory) throws SchedulerException;ListenerManager getListenerManager() throws SchedulerException;/**调度一个任务*/Date scheduleJob(JobDetail jobDetail, Trigger trigger)throws SchedulerException;Date scheduleJob(Trigger trigger) throws SchedulerException;void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException;void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) throws SchedulerException;/**取消调度 */boolean unscheduleJob(TriggerKey triggerKey)throws SchedulerException;boolean unscheduleJobs(List<TriggerKey> triggerKeys)throws SchedulerException;Date rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) throws SchedulerException;void addJob(JobDetail jobDetail, boolean replace)throws SchedulerException;void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling)throws SchedulerException;boolean deleteJob(JobKey jobKey)throws SchedulerException;boolean deleteJobs(List<JobKey> jobKeys)throws SchedulerException;void triggerJob(JobKey jobKey)throws SchedulerException;void triggerJob(JobKey jobKey, JobDataMap data)throws SchedulerException;void pauseJob(JobKey jobKey)throws SchedulerException;void pauseJobs(GroupMatcher<JobKey> matcher) throws SchedulerException;void pauseTrigger(TriggerKey triggerKey)throws SchedulerException;void pauseTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException;void resumeJob(JobKey jobKey)throws SchedulerException;void resumeJobs(GroupMatcher<JobKey> matcher) throws SchedulerException;void resumeTrigger(TriggerKey triggerKey)throws SchedulerException;void resumeTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException;void pauseAll() throws SchedulerException;void resumeAll() throws SchedulerException;List<String> getJobGroupNames() throws SchedulerException;Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher) throws SchedulerException;List<? extends Trigger> getTriggersOfJob(JobKey jobKey)throws SchedulerException;List<String> getTriggerGroupNames() throws SchedulerException;Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> matcher) throws SchedulerException;Set<String> getPausedTriggerGroups() throws SchedulerException;JobDetail getJobDetail(JobKey jobKey)throws SchedulerException;Trigger getTrigger(TriggerKey triggerKey)throws SchedulerException;TriggerState getTriggerState(TriggerKey triggerKey)throws SchedulerException;void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)throws SchedulerException;boolean deleteCalendar(String calName) throws SchedulerException;Calendar getCalendar(String calName) throws SchedulerException;List<String> getCalendarNames() throws SchedulerException;boolean interrupt(JobKey jobKey) throws UnableToInterruptJobException;boolean interrupt(String fireInstanceId) throws UnableToInterruptJobException;boolean checkExists(JobKey jobKey) throws SchedulerException; boolean checkExists(TriggerKey triggerKey) throws SchedulerException;void clear() throws SchedulerException;
}
StdScheduler
标准Scheduler,主要功能是通过内部的 QuartzScheduler
实现。
附录
参考
http://www.quartz-scheduler.org/documentation/quartz-2.3.0/cookbook/
http://www.quartz-scheduler.org/documentation/quartz-2.3.0/configuration/
配置
主要配置
属性名称 | 必需 | 类型 | 默认值 |
---|---|---|---|
org.quartz.scheduler.instanceName | no | string | ‘QuartzScheduler’ |
org.quartz.scheduler.instanceId | no | string | ‘NON_CLUSTERED’ |
org.quartz.scheduler.instanceIdGenerator.class | no | string (class name) | org.quartz.simpl .SimpleInstanceIdGenerator |
org.quartz.scheduler.threadName | no | string | instanceName + ‘_QuartzSchedulerThread’ |
org.quartz.scheduler .makeSchedulerThreadDaemon | no | boolean | false |
org.quartz.scheduler .threadsInheritContextClassLoaderOfInitializer | no | boolean | false |
org.quartz.scheduler.idleWaitTime | no | long | 30000 |
org.quartz.scheduler.dbFailureRetryInterval | no | long | 15000 |
org.quartz.scheduler.classLoadHelper.class | no | string (class name) | org.quartz.simpl .CascadingClassLoadHelper |
org.quartz.scheduler.jobFactory.class | no | string (class name) | org.quartz.simpl.PropertySettingJobFactory |
org.quartz.context.key.SOME_KEY | no | string | none |
org.quartz.scheduler.userTransactionURL | no | string (url) | ‘java:comp/UserTransaction’ |
org.quartz.scheduler .wrapJobExecutionInUserTransaction | no | boolean | false |
org.quartz.scheduler.skipUpdateCheck | no | boolean | false |
org.quartz.scheduler .batchTriggerAcquisitionMaxCount | no | int | 1 |
org.quartz.scheduler .batchTriggerAcquisitionFireAheadTimeWindow | no | long | 0 |
- org.quartz.scheduler.instanceName:实例名称,用来区分特定的调度器实例。
- org.quartz.scheduler.instanceId:实例Id,用来区分特定的调度器实例。在集群模式下,必须保证唯一。是物理上唯一,instanceName是逻辑上的区分。假如想Quartz帮生成这个值的话,可以设置为AUTO。
- org.quartz.scheduler.instanceIdGenerator.class:调度器实例id的生成方式,只有在调度器示例id设置为Auto自动生成时有效。缺省值org.quartz.simpl.SimpleInstanceIdGenerator。
- org.quartz.scheduler.threadName:调度器的线程名称,默认使用instanceName+’_QuartzSchedulerThread’
- org.quartz.scheduler.makeSchedulerThreadDaemon:是否将schedule主线程设置为守护线程,默认false
- org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer:Quartz生成的线程是否继承初始化线程的上下文类加载器,默认false
- org.quartz.scheduler.idleWaitTime:在调度程序空闲时,重复查询是否有可用触发器的等待时间,默认30000(毫秒)
- org.quartz.scheduler.dbFailureRetryInterval:JobStore 模式下,连接超时重试连接的间隔,默认15000(毫秒)
- org.quartz.scheduler.classLoadHelper.class:类加载帮助类,默认org.quartz.simpl.CascadingClassLoadHelper
- org.quartz.scheduler.jobFactory.class:指定JobFactory的类(接口)名称,负责实例化jobClass,默认值为org.quartz.simpl.PropertySettingJobFactory
- org.quartz.context.key.SOME_KEY:代替 “scheduler context” 的一些配置。“org.quartz.context.key.MyKey = MyValue” 等价于
scheduler.getContext().put(“MyKey”, “MyValue”)
. 事务相关属性应该被排除在配置文件之外,除非使用的是JTA事务 - org.quartz.scheduler.userTransactionURL:设置Quartz能够加载UserTransaction的JNDI的 URL。
- org.quartz.scheduler.wrapJobExecutionInUserTransaction:是否在Quartz执行一个job前使用UserTransaction
- org.quartz.scheduler.skipUpdateCheck:在程序运行前检查quartz是否有版本更新,默认false
- org.quartz.scheduler.batchTriggerAcquisitionMaxCount:允许调度程序一次性触发的触发器数量,默认值1。1、值越大表示允许触发的任务越多;2、如果值大于1时,需要设置
org.quartz.jobStore.acquireTriggersWithinLock
属性为true,以避免多个触发器产生的数据混乱。 - org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow:允许触发器被获取并在其预定的触发时间之前触发的数量,默认数量为0
线程池配置
- org.quartz.threadPool.class:线程池的实现类,一般默认使用
org.quartz.simpl.SimpleThreadPool
(固定大小)实例。 - org.quartz.threadPool.threadCount:线程池中的线程数量,默认10。如果仅几个任务,建议1,如果上万个,建议50–100。
- org.quartz.threadPool.threadPriority:线程的优先级,默认5。最小优先级1,最高10。
- org.quartz.threadPool.makeThreadsDaemons:是否设置为守护线程,默认false。
- org.quartz.threadPool.threadsInheritGroupOfInitializingThread:加载任务的代码的ClassLoader是否从外部继承,默认true
- org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread:
- org.quartz.threadPool.threadNamePrefix:线程默认的前缀,默认Worker 。
如果是自定义的线程池,则可以设置自定义的属性值
org.quartz.threadPool.class = MyThreadPool org.quartz.threadPool.attr1 = someValue //MyThreadPool的属性attr1 的值 org.quartz.threadPool.attr2 = someValue //MyThreadPool的属性attr2 的值
RAMJobStore
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.jobStore.misfireThreshold:最大能忍受的触发超时时间,默认值60000(毫秒),超时则认为失误。
数据连接配置
quartz框架中数据源相关的配置属性的统一前缀为:org.quartz.jobStore.
-
class,job的存储方式,可以选择存储在内存中或者持久化数据库中,默认为null
- org.quartz.simpl.RAMJobStore 即存储在内存中,不适用配置文件时默认值
- org.quartz.impl.jdbcjobstore.JobStoreTX 表示选择JDBC存储方式,自己管理事务
- org.quartz.impl.jdbcjobstore.JobStoreCMT也表示JDBC,但是由全局JTA管理事务
-
driverDelegateClass,用于处理不同数据库之间差异的实现类,默认null
- 使用mysql jdbc数据存储时设置为为org.quartz.impl.jdbcjobstore.StdJDBCDelegate
-
dataSource,配置数据源的名称,默认null
- 如果不配置数据源名称,可以使用spring配置文件中的数据源,并在scheduler创建时注入
- 如果此处配置了数据源的名称,可以进一步在quartz文件中配置数据源信息
# 配置数据源名称:`dataSoruce=dataSourceName` org.quartz.dataSource.dataSourceName.driver org.quartz.dataSource.dataSourceName.URL org.quartz.dataSource.dataSourceName.user org.quartz.dataSource.dataSourceName.password org.quartz.dataSource.dataSourceName.maxConnections
-
tablePrefix,表示quartz定时任务持久化时对应的数据表前缀,默认值
QRTZ_
-
misfireThreshold,最大能忍受的触发超时时间,默认值60000,超时则认为失误
-
useProperties,使用key-value的形式存储
JobDataMap
,默认true 指示JDBCJobStore所有的JobDataMaps中的值都是字符串,并且能以“名字-值”对的方式存储而不是以复杂对象的序列化形式存储在BLOB字段中,应该设置为true
-
isClustered,是否以集群方式运行,默认false
- 如果多个quartz实例使用同一个数据库,则需要设置为true,否则会报错
-
clusterCheckinInterval,检入到数据库中的频率,默认20000
-
maxMisfiresToHandleAtATime,JobStore处理未按时触发的Job数量,默认20
-
dontSetAutoCommitFalse,事务是否自动提交,默认false
-
selectWithLockSQL,配置加锁的SQL语句,默认false,需要配置时默认语句是:
SELECT * FROM [tableName] LOCKS WHERE LOCK_NAME = ? FOR UPDATE
- txIsolationLevelSerializable,是否使用事务隔离级别中的可序列化,默认false
- acquireTriggersWithinLock,触发事务前是否需要拥有锁,默认true
- lockHandler.class,用于管理数据库中相关锁机制的类名,默认null
Jdbc存储表结构
- qrtz_blob_triggers:以blob格式存放自定义trigger信息
- qrtz_calendars:记录quartz任务中的日历信息
- qrtz_cron_triggers:记录cronTrigger,即cron表达式相关触发器的信息
- qrtz_fired_triggers:存储正在触发的定时器的信息,执行完后数据清空
- qrtz_job_details:记录每个定时任务详细信息的表
- qrtz_locks:分布式处理时多个节点定时任务的锁信息
- qrtz_paused_triggers_grps:存储暂停的任务触发器信息
- qrtz_scheduler_state:记录调度器状态的表
- qrtz_simple_triggers:记录SimpleTrigger,即普通的触发器信息
- qrtz_simprop_triggers:存储CalendarIntervalTrigger和DailyTimeIntervalTrigger触发器信息
- qrtz_triggers:记录每个触发器详细信息的表
相关文章:

quartz使用及原理解析
quartz简介 Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能: 持久性作业 - 就是保持调度…...

Datawhale组队学习:大数据 D2——分布式文件系统(HDFS)
妙趣横生大数据 Day2三、Hadoop 分布式文件系统(HDFS)1. 分布式文件系统2. HDFS 简介3. HDFS 体系结构4. HDFS存储原理数据冗余存储数据存储策略数据错误与恢复5. HDFS数据读写过程读写过程HDFS故障类型和其检测方法HDFS编程实验1. 本地和集群文件间操作2. 基本文件操作3. Hado…...

CCIE重认证-300-401-拖图题全
拖图 拖图题 编程 snippet;192.168.5.0,mask 255.255.255.0;number是192.168.5.0;mask是255.255.255.0 snippets;edit-config对config,loopback对name 100,address对primary,mask…...
如何动态的创建类?type的其他用法?什么是元类,如何自定义元类?
1、python中一切都是对象,类也不例外,type是object的子类,是创建类的类。 如何动态的创建一个类? 用脚丫子创建 用脑子创建 不会 不知道什么事动态类 大家可能会有一堆的疑惑,是的我也是有很多疑惑那让我们一起来探个…...
XCP实战系列介绍15-XCP故障排查指导
本文框架 1.概述2. 通过调试器排查2.1 打开Det功能2.2 如何确定Det ErrorCode3. 通过XCP应答报文排查3.1 FE报文组成及故障码对应关系3.2 举个例子1.概述 前面几篇文章我们介绍了基于Davinci开发工具的XCP配置指导,配好了,代码也生成了,但是程序一定能正常跑起来吗?就算软…...

吉林大学软件需求分析与规范(Software Requirements Analysis Specification)
chapter0课程简介:◼ 软件工程专业核心课程之一◼ 软件工程课程体系最前端课程◼ 主要内容:需求的基本概念,需求的分类,需求工程的基本过程,需求获取的方法、步骤、技巧,需求分析和建模技术,需求…...

PyTorch - Conv2d 和 MaxPool2d
文章目录Conv2d计算Conv2d 函数解析代码示例MaxPool2d计算函数说明卷积过程动画Transposed convolution animationsTransposed convolution animations参考视频:土堆说 卷积计算 https://www.bilibili.com/video/BV1hE411t7RN 关于 torch.nn 和 torch.nn.function t…...
leetcode Day2(昨天实习有点bug,心态要崩了)
int carry 0;for(int i a.size() - 1, j b.size() - 1; i > 0 || j > 0 || carry; --i, --j) {int x i < 0 ? 0 : a[i] - 0;int y j < 0 ? 0 : b[j] - 0;int sum (x y carry) % 2;carry (x y carry) / 2;str.insert(0, 1, sum 0);}return str;加一&a…...
另一种思考:为什么不选JPA、MyBatis,而选择JDBCTemplate
以下内容转载自:https://segmentfault.com/a/1190000018472572 作者:scherman 因为项目需要选择数据持久化框架,看了一下主要几个流行的和不流行的框架,对于复杂业务系统,最终的结论是,JOOQ是总体上最好的…...
LeetCode 338. 比特位计数
给你一个整数 n ,对于 0 < i < n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n 1 的数组 ans 作为答案。 示例 1: 输入:n 2 输出:[0,1,1] 解释: 0 --> 0 1 --> …...

排序评估指标——NDCG和MAP
在搜索和推荐任务中,系统常返回一个item列表。如何衡量这个返回的列表是否优秀呢? 例如,当我们检索【推荐排序】,网页返回了与推荐排序相关的链接列表。列表可能会是[A,B,C,G,D,E,F],也可能是[C,F,A,E,D],现在问题来了…...

[Android Studio] Android Studio Virtual Device(AVD)虚拟机的功能试用
🟧🟨🟩🟦🟪 Android Debug🟧🟨🟩🟦🟪 Topic 发布安卓学习过程中遇到问题解决过程,希望我的解决方案可以对小伙伴们有帮助。 🚀write…...

kafka-3-kafka应用的核心要点和内外网访问
kafka实战教程(python操作kafka),kafka配置文件详解 Kafka内外网访问的设置 1 kafka简介 根据官网的介绍,ApacheKafka是一个分布式流媒体平台,它主要有3种功能: (1)发布和订阅消息流,这个功能类似于消息队列&#x…...

VS2017+OpenCV4.5.5 决策树-评估是否发放贷款
决策树是一种非参数的监督学习方法,主要用于分类和回归。 决策树结构 决策树在逻辑上以树的形式存在,包含根节点、内部结点和叶节点。 根节点:包含数据集中的所有数据的集合内部节点:每个内部节点为一个判断条件,并且…...

Prometheus 记录规则和警报规则
前提环境: Docker环境 涉及参考文档: Prometheus 录制规则Prometheus 警报规则 语法检查规则 promtool check rules /path/to/example.rules.yml一:录制规则语法 groups 语法: groups:[ - <rule_group> ]rule_group…...

(API)接口测试的关键技术
接口测试也就是API测试,从名字上可以知道是面向接口的测试活动。所以在讲API测试之前,我们应该说清楚接口是什么,那么接口就是有特定输入和特定输出的一套逻辑处理单元,而对于接口调用方来说,不用知道自身的内部实现逻…...

快速排序算法原理 Quicksort —— 图解(精讲) JAVA
快速排序是 Java 中 sort 函数主要的排序方法,所以今天要对快速排序法这种重要算法的详细原理进行分析。 思路:首先快速排序之所以高效一部分原因是利用了离散数学中的传递性。 例如 1 < 2 且 2 < 3 所以可以推出 1 < 3。在快速排序的过程中巧…...

linux环境搭建私有gitlab仓库
搭建之前,需要安装相应的依赖包,并且要启动sshd服务(1).安装policycoreutils-python openssh-server openssh-clients [rootVM-0-2-centos ~]# sudo yum install -y curl policycoreutils-python openssh-server openssh-clients [rootVM-0-2-centos ~]…...
SpringSecurity授权
文章目录工具类使用自定义失败处理代码配置跨域其他权限授权hasAnyAuthority自定义权限校验方法基于配置的权限控制工具类 import javax.servlet.http.HttpServletResponse; import java.io.IOException;public class WebUtils {/*** 将字符串渲染到客户端** param response 渲…...

学习 Python 之 Pygame 开发坦克大战(一)
学习 Python 之 Pygame 开发坦克大战(一)Pygame什么是Pygame?初识pygame1. 使用pygame创建窗口2. 设置窗口背景颜色3. 获取窗口中的事件4. 在窗口中展示图片(1). pygame中的直角坐标系(2). 展示图片(3). 给部分区域设置颜色5. 在窗口中显示文字6. 播放音…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...

android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...