架构师系列- 定时任务(二)- Quartz框架

quartz特点

Quartz是一个优秀的任务调度框架, 具有以下特点

  • 强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;
  • 负载均衡
  • 高可用
quartz 架构体系

Quartz 设计有四个核心类,分别是Scheduler(调度器)、Job(任务) 、Trigger(触发器)、JobDetail(任务详情),他们是使用Quartz的关键。

调度器作为作业的总指挥,触发器作为作业的操作者,作业为应用的功能模块,其关系如下图所示:

Job接口

定时任务的接口,具体定时任务需要实现该接口

定义需要执行的任务,该类是一个接口,只定义了一个方法execute(JobExecutionContext context),在实现类的execute方法中编写所需要定时执行的Job(任务),JobExcutionContext类提供了调度应用的一些信息。Job运行时的信息保存在JobDataMap实例中。

public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("开始执行定时任务...");}
}
Trigger接口

负责设置调度策略,该类是一个接口,描述触发job执行的时间触发规则

有以下这些子类,其中经常用到的是cronTigger

公共属性
  • triggerKey:表示Trigger身份的属性
  • jobKey:Trigger触发时被执行的Job的身份
  • startTime:Trigger第一次触发的时间
  • endTime:Trigger失效的时间点
  • 优先级(priority):如果Trigger很多,或者Quartz线程池的工作线程太少,Quartz可能没有足够的资源同时触发所有的Trigger,这种情况下,如果希望某些Trigger优先被触发,就需要给它设置优先级,Trigger默认的优先级为5,优先级priority属性的值可以是任意整数,正数、负数都可以。(只有同时触发的Trigger之间才会比较优先级)
SimpleTrigger

指定从某一个时间开始,以一定时间间隔(单位:毫秒)执行的任务

关键属性

  • repeatInterval:重复间隔
  • repeatCount:重复次数,实际执行次数是repeatCount+1(因为在startTime的时候一定会执行一次)

代码示例

TriggerBuilder.newTrigger()//设置Trigger的name以及group.withIdentity("my_job_tigger", "my_job_tigger_group")//trigger 开始生效时间.startAt(new Date(System.currentTimeMillis() + 5000))//调度策略.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).withRepeatCount(10))//trigger开始失效时间.endAt(new Date(System.currentTimeMillis() + 15000))//任务名词.forJob("自定义JOB").build();

 

CalendarIntervalTrigger

类似于SimpleTrigger,指定从某一个时间开始,以一定的时间间隔执行的任务

但是不同的是SimpleTrigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每月的时间间隔不是固定值),而CalendarIntervalTrigger支持的间隔单位有秒,分钟,小时,天,月,年,星期

优点

  1. 更方便,比如每隔1小时执行,你不用自己去计算1小时等于多少毫秒
  2. 支持不是固定长度的间隔,比如间隔为月和年。但劣势是精度只能到秒

关键属性

  • interval 执行间隔:intervalUnit 执行间隔的单位(秒,分钟,小时,天,月,年,星期)

代码示例

TriggerBuilder.newTrigger()//设置Trigger的name以及group.withIdentity("my_job_tigger", "my_job_tigger_group")//trigger 开始生效时间,马上生效.startNow()//调度策略.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withInterval(10, DateBuilder.IntervalUnit.SECOND))//trigger开始失效时间.endAt(new Date(System.currentTimeMillis() + 15000))//任务名词.forJob("calendar_tigger_test").build();
DailyTimeIntervalTrigger

指定每天的某个时间段内,以一定的时间间隔执行任务,并且它可以支持指定星期

关键属性

  • startTimeOfDay:每天开始时间
  • endTimeOfDay:每天结束时间
  • daysOfWeek:需要执行的星期

代码案例

TriggerBuilder.newTrigger()//设置Trigger的name以及group.withIdentity("my_job_tigger", "my_job_tigger_group")//trigger 开始生效时间.startNow()//调度策略.withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()//早上10点开始执行.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(10, 0))//晚上8点停止执行.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(20, 0))// 周一到周四执行,不写即每天执行.onDaysOfTheWeek(DateBuilder.MONDAY, DateBuilder.TUESDAY, DateBuilder.WEDNESDAY, DateBuilder.THURSDAY)//一小时执行一次.withIntervalInHours(1)//重复执行10次,总共执行11次.withRepeatCount(10))//trigger开始失效时间.endAt(new Date(System.currentTimeMillis() + 15000))//任务名词.forJob("calendar_tigger_test").build();
CronTrigger

适合于更复杂的任务,它支持类型于Linux Cron的语法(并且更强大)

代码案例

TriggerBuilder.newTrigger()//设置Trigger的name以及group.withIdentity("my_job_tigger", "my_job_tigger_group")//trigger 开始生效时间.startNow()//调度策略 每隔5S执行一次.withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))//trigger开始失效时间.endAt(new Date(System.currentTimeMillis() + 15000))//任务名词.forJob("calendar_tigger_test").build();

 

JobDetail

描述Job的实现类及其它相关的静态信息,如:Job名字、描述、关联监听器等信息

Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。

因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色,JobDetail 用来保存我们作业的详细信息。

一个JobDetail可以有多个Trigger,但是一个Trigger只能对应一个JobDetail

JobBuilder.newJob(MyJob.class).withIdentity("MyJob_1", "JobGroup_1").build();
Scheduler

调度器就相当于一个容器,装载着任务和触发器

Scheduler负责管理Quartz的运行环境,Quartz它是基于多线程架构的,它启动的时候会初始化一套线程,这套线程会用来执行一些预置的作业。

Trigger和JobDetail可以注册到Scheduler中,Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行

Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率

创建调度器

Scheduler接口有两个实现类,分别为StdScheduler(标准默认调度器)和RemoteScheduler(远程调度器),我们重点介绍下StdScheduler实例,StdScheduler只提供了一个带参构造方法,此构造需要传递QuartzScheduler和SchedulingContext两个实例参数

public StdScheduler(QuartzScheduler sched, SchedulingContext schedCtxt)

然而我们一般不使用构造方法去创建调度器,而是通过调度器工厂来创建,调度器工厂接口SchedulerFactory提供了两种不同类型的工厂实现,分别是DirectSchedulerFactoryStdSchedulerFactory

DirectSchedulerFactory一般用的比较少,更多的场景下我们使用StdSchedulerFactory工厂来创建

创建方式

StdSchedulerFactory提供三种方式创建调度器实例

  1. 通过java.util.Properties属性实例
  2. 通过外部属性文件提供
  3. 通过有属性文件内容的 java.io.InputStream 文件流提供
public static void main(String[] args) {try {StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();// 第一种方式 通过Properties属性实例创建Properties props = new Properties();props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, "org.quartz.simpl.SimpleThreadPool");props.put("org.quartz.threadPool.threadCount", 5);schedulerFactory.initialize(props);// 第二种方式 通过传入文件名// schedulerFactory.initialize("my.properties");// 第三种方式 通过传入包含属性内容的文件输入流// InputStream is = new FileInputStream(new File("my.properties"));// schedulerFactory.initialize(is);// 获取调度器实例Scheduler scheduler = schedulerFactory.getScheduler();} catch (Exception e) {e.printStackTrace();}}

 

集群方案

上面的单机方案存在着单点问题,如果定时任务在多个服务器上运行,则会重复触发,为了解决这些问题,就需要使用quartz的集群方案

集群架构

一个Quartz集群中的每个节点是一个独立的Quartz应用,它又管理着其他的节点。

这就意味着你必须对每个节点分别启动或停止,Quartz集群中,独立的Quartz节点并不与另一节点或是管理节点通信,而是通过相同的数据库表来感知到另一Quartz应用的。

初始化数据库 
docker run -itd --name mysql-quartz -p 3306:3306 -v /opt/scheduleTask/quartz:/opt -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7docker exec -it mysql-quartz bash
mysql> create database quartz default charset 'utf8';
mysql> use quartz;
mysql> source /opt/tables_mysql.sql

 

因为Quartz集群依赖于数据库,所以必须首先创建Quartz数据库表,Quartz发布包中包括了所有被支持的数据库平台的SQL脚本

这些SQL脚本存放于<quartz_home>/docs/dbTables 目录下找到对应数据库的SQL文件这里采用的是tables_mysql.sql

对应表简单含义如下

表明功能
QRTZ_CALENDARS以 Blob 类型存储 Quartz 的 Calendar 信息
QRTZ_CRON_TRIGGERS存储 Cron Trigger,包括 Cron 表达式和时区信息
QRTZ_FIRED_TRIGGERS存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
QRTZ_PAUSED_TRIGGER_GRPS存储已暂停的 Trigger 组的信息
QRTZ_SCHEDULER_STATE存储少量的有关 Scheduler 的状态信息,和别的 Scheduler 实例(假如是用于一个集群中)
QRTZ_LOCKS存储程序的悲观锁的信息(假如使用了悲观锁)
QRTZ_JOB_DETAILS存储每一个已配置的 Job 的详细信息
QRTZ_SIMPLE_TRIGGERS存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数
QRTZ_BLOG_TRIGGERSTrigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)
QRTZ_TRIGGER_LISTENERS存储已配置的 TriggerListener 的信息
QRTZ_TRIGGERS存储已配置的 Trigger 的信息
引入pom

将需要的pom文件引入

<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency><!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
<dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version>
</dependency>
编辑quartz.properties
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
#集群配置
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
#============================================================================
# Configure JobStore
#============================================================================
#默认配置,数据保存到内存
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#持久化配置
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties:true
#数据库表前缀
org.quartz.jobStore.tablePrefix:qrtz_
org.quartz.jobStore.dataSource:qzDS#============================================================================
# Configure Datasources
#============================================================================
#JDBC驱动
org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL:jdbc:mysql://192.168.10.30:3306/quartz
org.quartz.dataSource.qzDS.user:root
org.quartz.dataSource.qzDS.password:123456
org.quartz.dataSource.qzDS.maxConnection:10
整合SpringBoot
注册Quartz注册工厂
该类是将quartz自己创建的类交给spring进行管理以及自动注入@Component
public class QuartzJobFactory extends AdaptableJobFactory {@Autowiredprivate AutowireCapableBeanFactory capableBeanFactory;@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {//调用父类的方法Object jobInstance = super.createJobInstance(bundle);//进行注入capableBeanFactory.autowireBean(jobInstance);return jobInstance;}
}
注册调度工厂
@Configuration
public class QuartzConfig {@Autowiredprivate QuartzJobFactory jobFactory;@Beanpublic SchedulerFactoryBean schedulerFactoryBean() throws IOException {//获取配置属性PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));//在quartz.properties中的属性被读取并注入后再初始化对象propertiesFactoryBean.afterPropertiesSet();//创建SchedulerFactoryBeanSchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setQuartzProperties(propertiesFactoryBean.getObject());factory.setJobFactory(jobFactory);//支持在JOB实例中注入其他的业务对象factory.setApplicationContextSchedulerContextKey("applicationContextKey");factory.setWaitForJobsToCompleteOnShutdown(true);//这样当spring关闭时,会等待所有已经启动的quartz job结束后spring才能完全shutdown。factory.setOverwriteExistingJobs(false);//是否覆盖己存在的Jobfactory.setStartupDelay(10);//QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动return factory;}/*** 通过SchedulerFactoryBean获取Scheduler的实例** @return* @throws IOException* @throws SchedulerException*/@Bean(name = "scheduler")public Scheduler scheduler() throws IOException, SchedulerException {Scheduler scheduler = schedulerFactoryBean().getScheduler();return scheduler;}
}
配置Quartz数据源
默认 Quartz 的数据连接池是 c3p0,由于性能不太稳定,不推荐使用,因此我们将其改成driud数据连接池public class DruidConnectionProvider implements ConnectionProvider {/*** 常量配置,与quartz.properties文件的key保持一致(去掉前缀),同时提供set方法,Quartz框架自动注入值。** @return* @throws SQLException*///JDBC驱动public String driver;//JDBC连接串public String URL;//数据库用户名public String user;//数据库用户密码public String password;//数据库最大连接数public int maxConnection;//数据库SQL查询每次连接返回执行到连接池,以确保它仍然是有效的。public String validationQuery;private boolean validateOnCheckout;private int idleConnectionValidationSeconds;public String maxCachedStatementsPerConnection;private String discardIdleConnectionsSeconds;public static final int DEFAULT_DB_MAX_CONNECTIONS = 10;public static final int DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = 120;//Druid连接池private DruidDataSource datasource;@Overridepublic Connection getConnection() throws SQLException {return datasource.getConnection();}@Overridepublic void shutdown() throws SQLException {datasource.close();}@Overridepublic void initialize() throws SQLException {if (this.URL == null) {throw new SQLException("DBPool could not be created: DB URL cannot be null");}if (this.driver == null) {throw new SQLException("DBPool driver could not be created: DB driver class name cannot be null!");}if (this.maxConnection < 0) {throw new SQLException("DBPool maxConnectins could not be created: Max connections must be greater than zero!");}datasource = new DruidDataSource();try {datasource.setDriverClassName(this.driver);} catch (Exception e) {try {throw new SchedulerException("Problem setting driver class name on datasource: " + e.getMessage(), e);} catch (SchedulerException e1) {}}datasource.setUrl(this.URL);datasource.setUsername(this.user);datasource.setPassword(this.password);datasource.setMaxActive(this.maxConnection);datasource.setMinIdle(1);datasource.setMaxWait(0);datasource.setMaxPoolPreparedStatementPerConnectionSize(DEFAULT_DB_MAX_CONNECTIONS);if (this.validationQuery != null) {datasource.setValidationQuery(this.validationQuery);if (!this.validateOnCheckout) {datasource.setTestOnReturn(true);} else {datasource.setTestOnBorrow(true);}datasource.setValidationQueryTimeout(this.idleConnectionValidationSeconds);}}public String getDriver() {return driver;}public void setDriver(String driver) {this.driver = driver;}public String getURL() {return URL;}public void setURL(String URL) {this.URL = URL;}public String getUser() {return user;}public void setUser(String user) {this.user = user;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public int getMaxConnection() {return maxConnection;}public void setMaxConnection(int maxConnection) {this.maxConnection = maxConnection;}public String getValidationQuery() {return validationQuery;}public void setValidationQuery(String validationQuery) {this.validationQuery = validationQuery;}public boolean isValidateOnCheckout() {return validateOnCheckout;}public void setValidateOnCheckout(boolean validateOnCheckout) {this.validateOnCheckout = validateOnCheckout;}public int getIdleConnectionValidationSeconds() {return idleConnectionValidationSeconds;}public void setIdleConnectionValidationSeconds(int idleConnectionValidationSeconds) {this.idleConnectionValidationSeconds = idleConnectionValidationSeconds;}public DruidDataSource getDatasource() {return datasource;}public void setDatasource(DruidDataSource datasource) {this.datasource = datasource;}public String getDiscardIdleConnectionsSeconds() {return discardIdleConnectionsSeconds;}public void setDiscardIdleConnectionsSeconds(String discardIdleConnectionsSeconds) {this.discardIdleConnectionsSeconds = discardIdleConnectionsSeconds;}
}
创建完成之后,还需要在quartz.properties配置文件中设置以下数据源#数据库连接池,将其设置为druid
org.quartz.dataSource.qzDS.connectionProvider.class=cn.itcast.config.DruidConnectionProvider{"jobName":"myJob","groupName":"default","jobClass":"cn.itcast.quartz.MyJob","cronExpression":"0/5 * * * * ?","param":{"hello":"world"}
}
任务管理

默认quartz的功能是有限的,我们可以自己实现quartz的任务管理,比如添加、删除、暂停、运行定时任务

管理接口

该接口是定时任务的管理接口,可以对定时任务进行管理

public interface QuartzJobService {/*** 添加任务可以传参数* @param clazzName* @param jobName* @param groupName* @param cronExp* @param param*/void addJob(String clazzName, String jobName, String groupName, String cronExp, Map<String, Object> param);/*** 暂停任务* @param jobName* @param groupName*/void pauseJob(String jobName, String groupName);/*** 恢复任务* @param jobName* @param groupName*/void resumeJob(String jobName, String groupName);/*** 立即运行一次定时任务* @param jobName* @param groupName*/void runOnce(String jobName, String groupName);/*** 更新任务* @param jobName* @param groupName* @param cronExp* @param param*/void updateJob(String jobName, String groupName, String cronExp, Map<String, Object> param);/*** 删除任务* @param jobName* @param groupName*/void deleteJob(String jobName, String groupName);/*** 启动所有任务*/void startAllJobs();/*** 暂停所有任务*/void pauseAllJobs();/*** 恢复所有任务*/void resumeAllJobs();/*** 关闭所有任务*/void shutdownAllJobs();
}
管理实现类

该类是定时任务的具体实现,是实现了quartz的各种操作

@Service
public class QuartzJobServiceImpl implements QuartzJobService {private static final Logger log = LoggerFactory.getLogger(QuartzJobServiceImpl.class);@Autowiredprivate Scheduler scheduler;@Overridepublic void addJob(String clazzName, String jobName, String groupName, String cronExp, Map<String, Object> param) {try {// 启动调度器,默认初始化的时候已经启动
//            scheduler.start();//构建job信息Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(clazzName);JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, groupName).build();//表达式调度构建器(即任务执行的时间)CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExp);//按新的cronExpression表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, groupName).withSchedule(scheduleBuilder).build();//获得JobDataMap,写入数据if (param != null) {trigger.getJobDataMap().putAll(param);}scheduler.scheduleJob(jobDetail, trigger);} catch (Exception e) {log.error("创建任务失败", e);}}@Overridepublic void pauseJob(String jobName, String groupName) {try {scheduler.pauseJob(JobKey.jobKey(jobName, groupName));} catch (SchedulerException e) {log.error("暂停任务失败", e);}}@Overridepublic void resumeJob(String jobName, String groupName) {try {scheduler.resumeJob(JobKey.jobKey(jobName, groupName));} catch (SchedulerException e) {log.error("恢复任务失败", e);}}@Overridepublic void runOnce(String jobName, String groupName) {try {scheduler.triggerJob(JobKey.jobKey(jobName, groupName));} catch (SchedulerException e) {log.error("立即运行一次定时任务失败", e);}}@Overridepublic void updateJob(String jobName, String groupName, String cronExp, Map<String, Object> param) {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName, groupName);CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);if (cronExp != null) {// 表达式调度构建器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExp);// 按新的cronExpression表达式重新构建triggertrigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();}//修改mapif (param != null) {trigger.getJobDataMap().putAll(param);}// 按新的trigger重新设置job执行scheduler.rescheduleJob(triggerKey, trigger);} catch (Exception e) {log.error("更新任务失败", e);}}@Overridepublic void deleteJob(String jobName, String groupName) {try {//暂停、移除、删除scheduler.pauseTrigger(TriggerKey.triggerKey(jobName, groupName));scheduler.unscheduleJob(TriggerKey.triggerKey(jobName, groupName));scheduler.deleteJob(JobKey.jobKey(jobName, groupName));} catch (Exception e) {log.error("删除任务失败", e);}}@Overridepublic void startAllJobs() {try {scheduler.start();} catch (Exception e) {log.error("开启所有的任务失败", e);}}@Overridepublic void pauseAllJobs() {try {scheduler.pauseAll();} catch (Exception e) {log.error("暂停所有任务失败", e);}}@Overridepublic void resumeAllJobs() {try {scheduler.resumeAll();} catch (Exception e) {log.error("恢复所有任务失败", e);}}@Overridepublic void shutdownAllJobs() {try {if (!scheduler.isShutdown()) {// 需谨慎操作关闭scheduler容器// scheduler生命周期结束,无法再 start() 启动schedulerscheduler.shutdown(true);}} catch (Exception e) {log.error("关闭所有的任务失败", e);}}
}
API接口
通过实现该接口可以通过外部API对定时任务进行管理@RestController
@RequestMapping("/quartz")
public class QuartzController {private static final Logger log = LoggerFactory.getLogger(QuartzController.class);@Autowiredprivate QuartzJobService quartzJobService;/*** 添加新任务** @param configDTO* @return*/@RequestMapping("/addJob")public Object addJob(@RequestBody QuartzConfigDTO configDTO) {quartzJobService.addJob(configDTO.getJobClass(), configDTO.getJobName(), configDTO.getGroupName(), configDTO.getCronExpression(), configDTO.getParam());return HttpStatus.OK;}/*** 暂停任务** @param configDTO* @return*/@RequestMapping("/pauseJob")public Object pauseJob(@RequestBody QuartzConfigDTO configDTO) {quartzJobService.pauseJob(configDTO.getJobName(), configDTO.getGroupName());return HttpStatus.OK;}/*** 恢复任务** @param configDTO* @return*/@RequestMapping("/resumeJob")public Object resumeJob(@RequestBody QuartzConfigDTO configDTO) {quartzJobService.resumeJob(configDTO.getJobName(), configDTO.getGroupName());return HttpStatus.OK;}/*** 立即运行一次定时任务** @param configDTO* @return*/@RequestMapping("/runOnce")public Object runOnce(@RequestBody QuartzConfigDTO configDTO) {quartzJobService.runOnce(configDTO.getJobName(), configDTO.getGroupName());return HttpStatus.OK;}/*** 更新任务** @param configDTO* @return*/@RequestMapping("/updateJob")public Object updateJob(@RequestBody QuartzConfigDTO configDTO) {quartzJobService.updateJob(configDTO.getJobName(), configDTO.getGroupName(), configDTO.getCronExpression(), configDTO.getParam());return HttpStatus.OK;}/*** 删除任务** @param configDTO* @return*/@RequestMapping("/deleteJob")public Object deleteJob(@RequestBody QuartzConfigDTO configDTO) {quartzJobService.deleteJob(configDTO.getJobName(), configDTO.getGroupName());return HttpStatus.OK;}/*** 启动所有任务** @return*/@RequestMapping("/startAllJobs")public Object startAllJobs() {quartzJobService.startAllJobs();return HttpStatus.OK;}/*** 暂停所有任务** @return*/@RequestMapping("/pauseAllJobs")public Object pauseAllJobs() {quartzJobService.pauseAllJobs();return HttpStatus.OK;}/*** 恢复所有任务** @return*/@RequestMapping("/resumeAllJobs")public Object resumeAllJobs() {quartzJobService.resumeAllJobs();return HttpStatus.OK;}/*** 关闭所有任务** @return*/@RequestMapping("/shutdownAllJobs")public Object shutdownAllJobs() {quartzJobService.shutdownAllJobs();return HttpStatus.OK;}
}
测试

可以通过Postman通过接口动态对定时任务进行管理

添加定时任务

通过PostMan添加任务

添加完成后,可以在控制台看到任务正在执行

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/651342.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Access2019直接将数据导入SQL Server数据库中,再直接链接回来

Access2019 的数据表等&#xff0c;除了通过 SSMA 导入数据库外&#xff0c;还可以利用access2019 自身的外部数据导出功能来达到目的。本文将详细介绍这一操作过程。 一、命令行操作阶段 1.以SA这一超级用户登录SQL Server&#xff0c;创建一个数据库&#xff0c;例如“个人…

[华为od]给你一串未加密的字符串 str 100

题目&#xff1a; 题目描述&#xff1a; 给你一串未加密的字符串 str&#xff0c;通过对字符串的每一个字母进行改变来实现加密&#xff0c;加密方式 是在每一个字母str[i]偏移特定数组元素a[i]的量&#xff0c;数组a前三位已经赋值&#xff1a; a[0]1,a[1]2,a[2]4。 当 i…

Ansible一键部署zabbix+grafana+agent

目录 IP地址规划ansible安装分开部署安装zabbix-mysql安装zabbix-server安装zabbix-agent安装zabbix-grafana 一键部署自动发现 IP地址规划 名字地址主要安装软件ansible-server192.168.40.137zabbix-server、ansible、zabbix-mysqlzabbix-agent1192.168.40.138zabbix-agentza…

CyberData统一元数据服务

CyberData统一元数据服务功能完善&#xff0c;实现了湖仓平台元数据在整个平台的统一管理以及外部数据源元数据的主动发现和多计算引擎间元数据的互通互联。 同时&#xff0c;我们支持跨多元计算场景&#xff0c;以及在元数据基础上的统一数据权限管理和数据湖的自动化优化加速…

mac: docker安装及其Command not found: docker

已经安装了docker desktop&#xff0c;没安装的 点击安装 傻瓜式安装即可 接着打开终端&#xff1a;好一个 Comand not found:docker 看我不把你整顿&#xff0c;解决如下&#xff1a; 如果你在 macOS 上安装了 Docker Desktop&#xff0c;但是终端无法识别 docker 命令&…

【JVM】从i++到JVM栈帧

【JVM】从i到JVM栈帧 本篇博客将用两个代码例子&#xff0c;简单认识一下JVM与栈帧结构以及其作用 从i与i说起 先不急着看i和i&#xff0c;我们来看看JVM虚拟机&#xff08;请看VCR.JPG&#xff09; 我们初学JAVA的时候一定都听到过JAVA“跨平台”的特性&#xff0c;也就是…

Linux之线程管理

目录 第1关&#xff1a;创建线程 任务描述 相关知识 使用pthread_create函数创建线程 编程要求 答案&#xff1a; 第2关&#xff1a;线程挂起 任务描述 相关知识 使用pthread_join挂起线程 编程要求 答案&#xff1a; 第3关&#xff1a;线程终止 任务描述 相关知识 使用pthread…

运行游戏提示dll文件丢失,分享多种有效的解决方法

在我们日常频繁地利用电脑进行娱乐活动&#xff0c;特别是畅玩各类精彩纷呈的电子游戏时&#xff0c;常常会遭遇一个令人困扰的问题。当我们满怀期待地双击图标启动心仪的游戏程序&#xff0c;准备全身心投入虚拟世界时&#xff0c;屏幕上却赫然弹出一条醒目的错误提示信息&…

【中级软件设计师】上午题12-软件工程(3):项目活动图、软件风险、软件评审、软件项目估算

【中级软件设计师】上午题12-软件工程&#xff08;3&#xff09; 1 软件项目估算1.1 COCOMO估算模型1.2 COCOMOⅡ模型 2 进度管理2.1 gantt甘特图2.2 pert图2.3 项目活动图2.3.1 画项目图 3 软件配置管理4 软件风险4.1 风险管理4.2 风险识别4.3 风险预测4.4 风险评估4.5 风险控…

Rest微服务案例

Rest 父工程构建microservicecloud-api公共子模块Modulemicroservicecloud-provider-dept-8001部门微服务提供者Modulemicroservicecloud-consumer-dept-80部门微服务消费者Module 以Dept部门模块做一个微服务通用案例 Consumer消费者&#xff08;Client&#xff09;通过REST调…

react项目发布后,浏览器源码泄露的解决方案

在使用create-react-app时&#xff0c;打包生产环境npm run build&#xff0c;浏览器打开后仍然是可以看到源码的。源码都没上传&#xff0c;为啥线上能看到源码 。 例&#xff1a;线上与服务器 线上与源码 react-scripts build和npm run build 有什么不同 react-scripts bui…

PID算法学习

PID算法介绍 在过程控制中&#xff0c;按偏差的比例&#xff08;P&#xff09;、积分&#xff08;I&#xff09;和微分&#xff08;D&#xff09;进行控制的PID控制器&#xff08;亦称PID调节器&#xff09;是应用最为广泛的一种自动控制器。它具有原理简单&#xff0c;易于实…