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. 播放音…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...
篇章二 论坛系统——系统设计
目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...
Mac flutter环境搭建
一、下载flutter sdk 制作 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 1、查看mac电脑处理器选择sdk 2、解压 unzip ~/Downloads/flutter_macos_arm64_3.32.2-stable.zip \ -d ~/development/ 3、添加环境变量 命令行打开配置环境变量文件 ope…...
