spring的定时任务:

1)简单的有Java自带的Timer、 ScheduledExecutorService, Spring自带的Task。

2)相较复杂的分布式定时任务中间件有XXL-JOB、ElasticJob等。

选Quartz理由:

1)任务Tigger能够被持久化,这样即使在发布后,任务依然能够执行,不需要重新设定。

2)能够轻松暂停恢复触发器(即下次不会被调度)。

3)支持Calander,Cron表达式等复杂的触发器,可以灵活的编写复杂触发器。

一:使用Timer创建简单的定时任务

有两点问题需要注意:
1.scheduleAtFixedRate和schedule的区别:scheduleAtFixedRate会尽量减少漏掉调度的情况,如果前一次执行时间过长,导致一个或几个任务漏掉了,那么会补回来,而schedule过去的不会补,直接加上间隔时间执行下一次任务。

public class TimerDemo {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("TimerTask1 run" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));}},1000,5000);//延时1s,之后每隔5s运行一次}
}

有两点问题需要注意:
1.scheduleAtFixedRate和schedule的区别:scheduleAtFixedRate会尽量减少漏掉调度的情况,如果前一次执行时间过长,导致一个或几个任务漏掉了,那么会补回来,而schedule过去的不会补,直接加上间隔时间执行下一次任务。
2.同一个Timer下添加多个TimerTask,如果其中一个没有捕获抛出的异常,则全部任务都会终止运行。但是多个Timer是互不影响

二:使用ScheduledThreadPoolExecutor创建定时任务

public class SchedulerDemo {public static void main(String[] args) {ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(5);executorService.scheduleWithFixedDelay(new Runnable() {@Overridepublic void run() {String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));System.out.println("ScheduledThreadPoolExecutor1 run:"+now);}},1,2,TimeUnit.SECONDS);}
}

scheduleWithFixedDelay跟schedule类似,而scheduleAtFixedRate与scheduleAtFixedRate一样会尽量减少漏掉调度的情况

三:在springboot环境下使用@Scheduled创建定时任务

1、启动类添加@EnableScheduling
2、定时任务方法上添加@Scheduled

@Component
public class springScheduledDemo {@Scheduled(cron = "1/5 * * * * ?")public void testScheduled(){System.out.println("springScheduled run:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));}
}

这里的cron表达式我们可以参考网上的配置:
但是spring的@Scheduled只支持6位,年份是不支持的,带年份的7位格式会报错:Cron expression must consist of 6 fields (found 7 in “1/5 * * * * ? 2018”):cron表达式生成器:http://cron.ciding.cc/

@Scheduled 默认是单线程执行的,所以在需要的时候,我们可以设置一个线程池去执行定时任务。

通过实现SchedulingConfigurer接口来将定时线程池放入

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;@Configuration
public class TaskConfig implements SchedulingConfigurer {@Beanpublic TaskScheduler taskScheduler() {ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();executor.setPoolSize(10);executor.setThreadNamePrefix("task-thread");//设置饱和策略//CallerRunsPolicy:线程池的饱和策略之一,当线程池使用饱和后,直接使用调用者所在的线程来执行任务;如果执行程序已关闭,则会丢弃该任务executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}//配置@Scheduled 定时器所使用的线程池//配置任务注册器:ScheduledTaskRegistrar 的任务调度器@Overridepublic void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {//可配置两种类型:TaskScheduler、ScheduledExecutorService//scheduledTaskRegistrar.setScheduler(taskScheduler());//只可配置一种类型:taskSchedulerscheduledTaskRegistrar.setTaskScheduler(taskScheduler());}}

使用Quartz定时任务框架:

1、使用SpringBoot2.x 版本集成 Quartz
2、Quartz 的任务动态实现:
3、调度任务可以通过页面进行新增、删除、启动、暂定等操作
4、任务数据使用数据库保存
5、任务之间实现简单的依赖
6、Quartz 实现分布式调度,使用其本身提供的基于数据库的实现

SpringBoot2 集成 Quartz

1、SpringBoot不同的版本对于Quartz 的集成有一定的差别,本文使用 2.1.2.RELEASE 版本。其实通过分析SpringBoot对于Quartz的自动化配置源码,也有助于我们理解Quartz的使用
2、SpringBoot-2.1.2.RELEASE 版本已经集成了对于Quartz的自动化配置,其源码路径为org.springframework.boot.autoconfigure.quartz
Pom依赖

    # Web工程<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency># quartz<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency># 数据库JDBC<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency># 使用MySql<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency>

编码功能实现
由于Springboot2的自动化配置,不需要做任何配置,直接写JobDetail、Trigger、Job 即可实现

# Job 实现
@DisallowConcurrentExecution
public class DemoJob extends QuartzJobBean {@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {System.out.println("~~ DemoJob 启动运行汇总~~");}
}# JobDetail、Trigger Bean配置
@Configuration
public class QuartzJobConfig {@Beanpublic JobDetailFactoryBean jobDetailFactoryBean() {JobDetailFactoryBean jobDetail = new JobDetailFactoryBean();jobDetail.setName("DemoJob");jobDetail.setGroup("DemoJob_Group");jobDetail.setJobClass(DemoJob.class);jobDetail.setDurability(true);return jobDetail;}@Beanpublic CronTriggerFactoryBean cronTriggerFactoryBean() {CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();trigger.setJobDetail(jobDetailFactoryBean().getObject());trigger.setCronExpression("*/10 * * * * ?");trigger.setName("DemoJob");trigger.setMisfireInstruction(0);return trigger;}
}

这样就实现了 SpringBoot2.x 版本集成 Quartz 功能,在进行下一步之前,我们先对自动化配置的源码简单分析一下。
SpringBoot关于Quartz的自动配置的类一共有6个,分别为:

  1. JobStoreType:是一个枚举类,定义了jobsStore的类型,基于内存和数据库
  2. QuartzAutoConfiguration:自动配置类,配置了Quartz的主要组件,如SchedulerFactoryBean
  3. QuartzDataSource:是一个注解类。如果需要注入Quartz配置的数据库操作类,需要使用此注解标注。参考QuartzAutoConfiguration中的用法
  4. QuartzDataSourceInitializer:该类主要用于数据源初始化后的一些操作,根据不同平台类型的数据库进行选择不同的数据库脚本
  5. QuartzProperties:该类对应了在application.yml配置文件以spring.quartz开头的相关配置
  6. SchedulerFactoryBeanCustomizer:在自动配置的基础上自定义配置需要实现的此接口。

QuartzAutoConfiguration

  • 初始化注入任务以及配置:构造函数实现
  • 注入了属性配置文件类:QuartzProperties
  • 注入了自定义扩展配置:SchedulerFactoryBeanCustomizer
  • 注入了Quartz的任务组件:JobDetail、Trigger、Calendar。所以我们只- 需要进行 JobDetail、Trigger Bean配置,会自动注入进QuartzAutoConfiguration类中,这边是通过ObjectProvider的使用实现的。
    public QuartzAutoConfiguration(QuartzProperties properties,ObjectProvider<SchedulerFactoryBeanCustomizer> customizers,ObjectProvider<JobDetail[]> jobDetails,ObjectProvider<Map<String, Calendar>> calendars,ObjectProvider<Trigger[]> triggers, ApplicationContext applicationContext) {this.properties = properties;this.customizers = customizers;this.jobDetails = jobDetails.getIfAvailable();this.calendars = calendars.getIfAvailable();this.triggers = triggers.getIfAvailable();this.applicationContext = applicationContext;}
2、配置 SchedulerFactoryBean 的详细信息。这个类是一个 FactoryBean。
  • 配置 JobFactory,内部设置了applicationContext与spring容器结合
  • 配置各种属性,是通过QuartzProperties类实现
  • 配置注入进来的 JobDetail、Trigger、Calendar
  • 配置自定配置,是通过SchedulerFactoryBeanCustomizer实现。这边包括自定义,也包括基于数据库实现的JobStore配置。
# 注释掉内存存储
# org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX 
    @Bean@ConditionalOnMissingBeanpublic SchedulerFactoryBean quartzScheduler() {# 配置 `JobFactory`SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();jobFactory.setApplicationContext(this.applicationContext);schedulerFactoryBean.setJobFactory(jobFactory);# 开始配置各种属性if (this.properties.getSchedulerName() != null) {schedulerFactoryBean.setSchedulerName(this.properties.getSchedulerName());}schedulerFactoryBean.setAutoStartup(this.properties.isAutoStartup());schedulerFactoryBean.setStartupDelay((int) this.properties.getStartupDelay().getSeconds());schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(this.properties.isWaitForJobsToCompleteOnShutdown());schedulerFactoryBean.setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs());if (!this.properties.getProperties().isEmpty()) {schedulerFactoryBean.setQuartzProperties(asProperties(this.properties.getProperties()));}# 配置 jobDetails、triggers等if (this.jobDetails != null && this.jobDetails.length > 0) {schedulerFactoryBean.setJobDetails(this.jobDetails);}if (this.calendars != null && !this.calendars.isEmpty()) {schedulerFactoryBean.setCalendars(this.calendars);}if (this.triggers != null && this.triggers.length > 0) {schedulerFactoryBean.setTriggers(this.triggers);}# 自定义配置customize(schedulerFactoryBean);return schedulerFactoryBean;}

3、基于数据库实现的 JobStore 配置,内部类JdbcStoreTypeConfiguration

  • @ConditionalOnSingleCandidate(DataSource.class) 指定pring容器中有且只有一个指明的DataSourceBean时生效
  • 通过dataSourceCustomizer方法实现schedulerFactoryBean的数据库相关配置,该方法返回一个 SchedulerFactoryBeanCustomizer。
  • 配置QuartzDataSourceInitializer 数据库初始化 Bean
  • 通过后置工厂处理器 DataSourceInitializerSchedulerDependencyPostProcessor 实现对于QuartzDataSourceInitializer这个Bean的依赖关系(dependsOn)
        @Bean@Order(0)public SchedulerFactoryBeanCustomizer dataSourceCustomizer(QuartzProperties properties, DataSource dataSource,@QuartzDataSource ObjectProvider<DataSource> quartzDataSource,ObjectProvider<PlatformTransactionManager> transactionManager) {return (schedulerFactoryBean) -> {# 判断是否为 JobStoreif (properties.getJobStoreType() == JobStoreType.JDBC) {# 获取 DataSourceDataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);# 配置 DataSource 和 TransactionManager管理schedulerFactoryBean.setDataSource(dataSourceToUse);PlatformTransactionManager txManager = transactionManager.getIfUnique();if (txManager != null) {schedulerFactoryBean.setTransactionManager(txManager);}}};}

支持功能配置 QuartzProperties

1、@ConfigurationProperties(“spring.quartz”) 以spring.quartz开头的配置
2、SpringBoot 已经做了相应的默认值处理,即使不做任何配置,也是没有问题的。
3、比较简单,直接贴码。属性的具体含义,任务调度

spring:quartz:scheduler-name: springboot-quartz-jdbc-dynamicauto-startup: falsestartup-delay: 5soverwrite-existing-jobs: falsewait-for-jobs-to-complete-on-shutdown: truejob-store-type: memory#    jdbc:#      initialize-schema: embedded#      schema: classpath:org/quartz/impl/jdbcjobstore/tables_@@platform@@.sql#      comment-prefix: --properties: {org.quartz.scheduler.instanceName: springboot-quartz-jdbc-dynamic,org.quartz.scheduler.instanceId: AUTO,org.quartz.threadPool.class: org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor,org.quartz.threadPool.threadCount: 25,org.quartz.threadPool.threadPriority: 5,org.quartz.jobStore.misfireThreshold: 60000,#      org.quartz.jobStore.tablePrefix: QRTZ_,#      org.quartz.jobStore.isClustered: true,#      org.quartz.jobStore.clusterCheckinInterval: 20000,#      org.quartz.jobStore.maxMisfiresToHandleAtATime: 1,#      org.quartz.jobStore.txIsolationLevelSerializable: false}

Quartz 实现分布式调度

配置简单实现
上述完成的 SpringBoot与Quartz的集成,可以看到有几个先关的配置:
1、job-store-type 可以选择JDBC完成分布式JdbcJobStore切换
2、jdbc.XXX 主要是对于初始化SQL的配置。
3、对于JdbcJobStore 的一些特殊配置,如表前缀、集群指定、数据库检查等,基于RamJobStore时,这些是不允许配置的。

将类型转换成 JobStoreTX

JobStoreTX 全称是: org.quartz.impl.jdbcjobstore.JobStoreTX

# 注释掉内存存储
# org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX 

三、 配置驱动代理

##驱动代理为 标准的jdbc
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate 

StdJDBCDelegate 为标准的jdbc。

四、配置数据库表前缀和数据源

#数据库表前缀
org.quartz.jobStore.tablePrefix:qrtz_
#数据源
org.quartz.jobStore.dataSource:yjlDB #JDBC驱动
org.quartz.dataSource.yjlDB.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.yjlDB.URL:jdbc:mysql://localhost:3306/quartz
org.quartz.dataSource.yjlDB.user:root
org.quartz.dataSource.yjlDB.password:您的数据库密码

五、最终 quartz.properties 配置文件内容


org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: falseorg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: trueorg.quartz.jobStore.misfireThreshold: 60000# 注释掉内存存储
# org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
##驱动代理为 标准的jdbc
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#数据库表前缀
org.quartz.jobStore.tablePrefix:qrtz_
#数据
org.quartz.jobStore.dataSource:yjlDB #JDBC驱动
org.quartz.dataSource.yjlDB.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.yjlDB.URL:jdbc:mysql://localhost:3306/quartz
org.quartz.dataSource.yjlDB.user:root
org.quartz.dataSource.yjlDB.password:abc123

持久化演示

编写任务 MyJobStoreTX

package com.yjl.jdbc;import java.text.SimpleDateFormat;
import java.util.Date;import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;/*** * @author 两个蝴蝶飞* 简单的 JobStoreTx 存储时的任务**/
public class MyJobStoreTX implements Job{@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String nowDate=sdf.format(new Date());System.out.println("MyJobStoreTX 备份数据库的时间是:"+nowDate);}}

编写主程序 MyJobStoreTxDemo

//测试 JobStoreTX 存储
public class MyJobStoreTxDemo {public static void main(String[] args) throws Exception {// 获取SchedulerScheduler scheduler = StdSchedulerFactory.getDefaultScheduler();JobDetail jobDetail = JobBuilder.newJob(MyJobStoreTX.class).withIdentity("jobTX1", "groupTX1").storeDurably(true).build();// 创建 TriggerTrigger trigger = TriggerBuilder.newTrigger().withIdentity("triggerTX1", "groupTX1") // 设置标识.startNow()// 每隔3秒执行一次.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")).build();// 关联 job和 triggerscheduler.scheduleJob(jobDetail, trigger);// 启动 schedulerscheduler.start();}
}


每隔两秒,运行一次。

查看数据库的 qrtz_cron_triggers 表内容:

查看数据库的 qrtz_job_details 表内容:

查看数据库的 qrtz_triggers 表内容:

将 JobDetail, Trigger 的内容放置到了数据库里面,进行了持久性的保存。

  • https://blog.csdn.net/yjltx1234csdn/article/details/105871616
  • https://www.w3cschool.cn/quartz_doc/quartz_doc-i7oc2d9l.html

【Spring】定时任务相关推荐

  1. Spring定时任务的几种实现

    Spring定时任务的几种实现 spring框架 quartz spring spring-task 定时任务 注解 近日项目开发中需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信 ...

  2. (转)Spring定时任务的几种实现

    Spring定时任务的几种实现 博客分类: spring框架 quartzspringspring-task定时任务注解  Spring定时任务的几种实现 近日项目开发中需要执行一些定时任务,比如需要 ...

  3. spring定时任务

    使用spring定时任务包Quartz时,必须使用Quartz1.85以下版本的. 查看发现spring3.0.5中org.springframework.scheduling.quartz.Cron ...

  4. Spring定时任务并行(异步)处理

    最近项目中遇到一个问题 , 在SpringBoot中设置了定时任务之后 , 在某个点总是没有执行 . 经过搜索研究发现 , spring 定时器任务scheduled-tasks默认配置是单线程串行执 ...

  5. Spring定时任务@scheduled多线程的使用(@Async注解)

    1.开篇 在Spring定时任务@Scheduled注解使用方式浅窥这篇文章里面提及过,spring的定时任务默认是单线程的,他在某些场景下会造成堵塞,那么如果我们想让每一个任务都起一条线程去执行呢? ...

  6. spring定时任务执行两次的原因与解决方法

    spring定时任务执行两次的原因与解决方法 参考文章: (1)spring定时任务执行两次的原因与解决方法 (2)https://www.cnblogs.com/yolanda-lee/p/7339 ...

  7. Spring定时任务高级使用篇

    Spring定时任务高级使用篇 前面一篇博文 <Spring之定时任务基本使用篇> 介绍了Spring环境下,定时任务的简单使用姿势,也留了一些问题,这一篇则希望能针对这些问题给个答案 I ...

  8. spring定时任务需要在项目启动时执行一次

    spring定时任务需要在项目启动时执行一次,然后再按照指定规则执行 在定时任务方法上加注解@PostConstruct,不是spring提供的注解,是JAVA原生注解,在初始化servlet之前执行 ...

  9. 浅谈Spring定时任务

    浅谈Spring定时任务 三种定时任务基于原理 多定时任务并发配置 动态定时任务 定时任务Demo 三种定时任务基于原理 SpringBoot配置定时任务主要有Spring Schedule.JDK自 ...

  10. 解决spring定时任务执行两次和tomcat部署缓慢的问题

    解决spring定时任务执行两次和tomcat部署缓慢的问题 参考文章: (1)解决spring定时任务执行两次和tomcat部署缓慢的问题 (2)https://www.cnblogs.com/Si ...

最新文章

  1. jira 审批流程_博兴县行政审批服务局推暖心服务工程 企业开办实现“全程网办”_博兴新闻...
  2. [FJOI2007]轮状病毒
  3. Python编码规范:IF中的多行条件
  4. bzoj1588 [HNOI2002]营业额统计
  5. PHP 基本语法,变量
  6. 同事说他的应用起不来了,因为我的代码里面多了一个空格!
  7. android 获取动态时间间隔,android 获取时间间隔
  8. Mysq数据库备份(win)
  9. Java-ReentrantLock-NonfairSync/FairSync
  10. pycharm直接显示所有show value的值(直接打开所有的值)
  11. 简单的jQuery获取URL的?后带的参数
  12. TIME_WAIT状态过多的排查
  13. android其架构图,Android系统架构图,带你直观了解Android基本架构
  14. 工具篇:金蝶K3工具下载
  15. STM32F103学习笔记(4)—— 串口通信——发送、接收数据详解
  16. setw()使用方法
  17. java timer异常_JAVA Timer的缺陷以及解决办法
  18. 【potplayer安装及设置LAV Splitter】
  19. 我对职业规划和未来发展的一些思考
  20. Zerg虫族的传说[官方资料]

热门文章

  1. 求值:空间向量的法向量
  2. html 图片重叠效果,CSS实现照片堆叠效果的实例代码
  3. mysql的prepared statement
  4. 配置云服务器+bt面板搭建自己的服务器
  5. (转载)简述马尔可夫链
  6. 百度AI人脸识别怎么实现,图片识别,文字识别,活体检测
  7. 英飞凌芯片支持计划第二阶段申请计划(硅麦芯片已开启)
  8. [附源码]Java计算机毕业设计SSM动物园动物饲养管理
  9. php导出excel 细边框,phpexcel设置边框不全或者只有竖线问题解决 方法
  10. Java转Go语言 -4