Quartz是一个开源的任务调度框架,可以用来实现定时任务的调度,如定时发送邮件、定时备份数据等。Quartz具有很高的可靠性和灵活性,支持集群部署和分布式调度,并且提供了丰富的API和插件,可以轻松实现复杂的调度需求。Quartz的工作原理是通过Job和Trigger两个核心概念来实现的,Job是具体需要执行的任务,Trigger用来触发任务的执行时机。在Quartz中,可以通过定义各种Trigger来实现不同的调度策略,如简单调度、Cron调度等。Quartz还提供了很多内置的Job和Trigger实现,如邮件发送、HTTP请求等,可以方便地用来实现常见的任务调度需求。
Quartz的核心组件包含Scheduler、Job和Trigger。这三个核心组件共同组成了Quartz的任务调度机制,使得开发人员可以通过配置简单的定时任务来实现复杂的调度策略。
是Quartz的核心组件,它负责调度和执行任务。Scheduler有一个任务管理器,负责维护任务列表,并根据Triggers的定义来决定何时执行任务。Scheduler还提供了API,通过API可以动态地添加、删除和修改任务。
管理作业:Scheduler负责管理Quartz中的所有作业,包括创建、修改和删除作业。
触发器管理:Scheduler负责管理Quartz中的所有触发器,包括创建、修改和删除触发器。
作业执行:Scheduler负责执行Quartz中的所有作业,并记录作业执行情况。
调度管理:Scheduler负责管理Quartz的整个调度过程,包括启动调度器、暂停调度器和恢复调度器。
监控和统计:Scheduler提供了各种监控和统计信息,以帮助开发人员了解Quartz的运行状况。
Job是一个接口,它定义了需要执行的逻辑,开发人员需要实现该接口,并在其中编写需要执行的业务逻辑。
Trigger是一个定义了任务执行时间的对象,Quartz提供了多种类型的Trigger,例如
SimpleTrigger:简单触发器,用于在指定时间执行一次或者按照指定的时间间隔重复执行。
CronTrigger:Cron触发器,用于按照类似于Unix/Linux系统中Cron表达式的方式指定复杂的时间计划,例如每周五下午五点执行。
CalendarIntervalTrigger:日历间隔触发器,用于按照在指定时间间隔内执行的时间计划,例如每隔一小时执行一次。
DailyTimeIntervalTrigger:每日时间间隔触发器,用于按照每日指定时间间隔执行的时间计划,例如每天上午10点和下午3点各执行一次。
我这里采用jdk17 Springboot3.1.2+mybatis-flex+openapi3与mysql来实现一个动态控制任务的demo
- <properties>
- <java.version>17java.version>
- <mybatis-flex.version>1.7.2mybatis-flex.version>
- <fastjson.version>1.2.47fastjson.version>
- properties>
-
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>com.github.xiaoymingroupId>
- <artifactId>knife4j-dependenciesartifactId>
- <version>4.1.0version>
- <type>pomtype>
- <scope>importscope>
- dependency>
- dependencies>
- dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
- <dependency>
- <groupId>com.github.xiaoymingroupId>
- <artifactId>knife4j-openapi3-jakarta-spring-boot-starterartifactId>
- dependency>
-
- <dependency>
- <groupId>com.mysqlgroupId>
- <artifactId>mysql-connector-jartifactId>
- <scope>runtimescope>
- dependency>
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <optional>trueoptional>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-jdbcartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-quartzartifactId>
- dependency>
- <dependency>
- <groupId>com.mybatis-flexgroupId>
- <artifactId>mybatis-flex-spring-boot-starterartifactId>
- <version>${mybatis-flex.version}version>
- dependency>
- <dependency>
- <groupId>com.alibabagroupId>
- <artifactId>fastjsonartifactId>
- <version>${fastjson.version}version>
- dependency>
- dependencies>
- mybatis-flex:
- datasource:
- ds1:
- url: jdbc:mysql://127.0.0.1:3306/test
- username: root
- password: zkb.com
- springdoc:
- swagger-ui:
- path: /swagger-ui.html
- tags-sorter: alpha
- api-docs:
- path: /v3/api-docs
- group-configs:
- - group: '接口'
- paths-to-match: '/**'
- packages-to-scan: com.zxs.springbootmybatisflex.controller.client
- default-flat-param-object: true
-
- package com.zxs.springbootmybatisflex.quartz;
-
- import com.zxs.springbootmybatisflex.entity.SysJob;
- import com.zxs.springbootmybatisflex.zenum.JobEnum;
- import org.quartz.Job;
- import org.quartz.JobExecutionContext;
-
- public class QuartzJob implements Job {
-
- @Override
- public void execute(JobExecutionContext context) {
- SysJob sysJob = (SysJob) context.getJobDetail().getJobDataMap().get(JobEnum.Key.getCode());
- QuartzUtil.runJob(sysJob.getInvokeTarget());
- }
- }
-
- package com.zxs.springbootmybatisflex.quartz;
-
- import com.zxs.springbootmybatisflex.entity.JobVo;
- import com.zxs.springbootmybatisflex.entity.SysJob;
- import com.zxs.springbootmybatisflex.uitl.SpringContextHolder;
- import com.zxs.springbootmybatisflex.zenum.ActionEnum;
- import com.zxs.springbootmybatisflex.zenum.JobEnum;
- import lombok.SneakyThrows;
- import org.quartz.*;
- import org.springframework.util.ObjectUtils;
-
- import java.lang.reflect.Method;
- import java.util.Date;
-
- public class QuartzUtil {
-
- @SneakyThrows
- public static void startJob(SysJob sysJob) {
- // 获取调度器 Scheduler
- Scheduler scheduler = SchedulerStatic.getScheduler();
- Integer jobId = sysJob.getJobId();
- String jobGroup = sysJob.getJobGroup();
-
- // 构造一个job
- JobKey jobKey = JobKey.jobKey(jobId.toString(), jobGroup);
- JobDetail jobDetail = JobBuilder
- .newJob(QuartzJob.class)
- .withIdentity(jobKey)
- .build();
-
- // 构造cron调度器
- CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(sysJob.getCronExpression());
- getMisfirePolicy(sysJob, cronScheduleBuilder);
-
- // 构造触发器 trigger
- TriggerKey triggerKey = TriggerKey.triggerKey(jobId.toString(), jobGroup);
- CronTrigger trigger = TriggerBuilder
- .newTrigger()
- .withIdentity(triggerKey)
- .withSchedule(cronScheduleBuilder)
- .build();
-
- // 放入job信息,为后续执行改任务的具体方法做铺垫(需要反射调用), 在execute中获取并应用
- jobDetail.getJobDataMap().put(JobEnum.Key.getCode(), sysJob);
- // 判断该任务是否存在,修改任务,先删除然后添加
- if (scheduler.checkExists(jobKey)) {
- // 防止创建时存在数据问题 先移除,然后在执行创建操作
- scheduler.deleteJob(jobKey);
- }
- // 判断任务是否过期
- CronExpression cron = new CronExpression(sysJob.getCronExpression());
- Date nextValidTimeAfter = cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
- if (!ObjectUtils.isEmpty(nextValidTimeAfter)) {
- // 执行调度任务
- scheduler.scheduleJob(jobDetail, trigger);
- }
- }
-
-
- @SneakyThrows
- public static void doJob(JobVo sysJob,String action) {
- // 获取调度器 Scheduler
- Scheduler scheduler = SchedulerStatic.getScheduler();
- // 构造一个job
- JobKey jobKey = JobKey.jobKey(sysJob.getJobId().toString(), sysJob.getJobGroup());
- // 判断该任务是否存在,修改任务,先删除然后添加
- if (!scheduler.checkExists(jobKey)) {
- return;
- }
- switch (action){
- case ActionEnum.check: //
- System.out.println(true);
- break;
- case ActionEnum.pause: //暂停
- scheduler.pauseJob(jobKey);
- break;
- case ActionEnum.resume: //继续
- scheduler.resumeJob(jobKey);
- break;
- case ActionEnum.delete: //删除
- scheduler.deleteJob(jobKey);
- break;
- default:
- scheduler.checkExists(jobKey);
- break;
- }
-
- }
-
- private static void getMisfirePolicy(SysJob sysJob, CronScheduleBuilder cronScheduleBuilder) {
- String s= sysJob.getMisfirePolicy();
- if(s.equals(JobEnum.MISFIRE_DEFAULT.getCode())){
- }else if(s.equals(JobEnum.MISFIRE_IGNORE.getCode())){
- cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
- } else if(s.equals(JobEnum.MISFIRE_FIRE_AND_PROCEED.getCode())){
- cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed();
- } else if(s.equals(JobEnum.MISFIRE_DO_NOTHING.getCode())){
- cronScheduleBuilder.withMisfireHandlingInstructionDoNothing();
- }else{
- throw new RuntimeException("The task misfire policy '" + sysJob.getMisfirePolicy() + "' cannot be used in cron schedule tasks");
- }
- }
-
- public static void invokeMethod(Object bean, String methodName) throws Exception {
- Method method = bean.getClass().getMethod(methodName);
- method.invoke(bean);
- }
- public static void runJob(String invokeTarget){
- String[] parts = invokeTarget.split("\\.");
- String beanName = parts[0];
- String methodName = parts[1];
- Object bean = SpringContextHolder.getBean(beanName);
- try {
- QuartzUtil.invokeMethod(bean, methodName);
- } catch (Exception e) {
- throw new RuntimeException("Error running job", e);
- }
- }
-
-
- }
- package com.zxs.springbootmybatisflex.quartz;
-
- import org.quartz.Scheduler;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
-
- @Component
- public class SchedulerStatic {
-
- private static Scheduler scheduler;
-
- @Autowired
- public SchedulerStatic(Scheduler scheduler) {
- SchedulerStatic.scheduler = scheduler;
- }
-
- public static Scheduler getScheduler() {
- return scheduler;
- }
- }
- package com.zxs.springbootmybatisflex.config;
-
- import org.springframework.cache.annotation.EnableCaching;
- import org.springframework.context.annotation.Configuration;
-
- @EnableCaching
- @Configuration
- public class CacheConfig {
- }
- package com.zxs.springbootmybatisflex.config;
-
- import com.mybatisflex.core.mybatis.FlexConfiguration;
- import com.mybatisflex.spring.boot.ConfigurationCustomizer;
- import org.apache.ibatis.logging.stdout.StdOutImpl;
- import org.springframework.context.annotation.Configuration;
-
- @Configuration
- public class MyConfigurationCustomizer implements ConfigurationCustomizer {
-
- @Override
- public void customize(FlexConfiguration configuration) {
- configuration.setLogImpl(StdOutImpl.class);
- }
- }
- package com.zxs.springbootmybatisflex.config;
-
- import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
- import io.swagger.v3.oas.models.OpenAPI;
- import io.swagger.v3.oas.models.info.Info;
- import io.swagger.v3.oas.models.info.License;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- @Configuration
- @EnableKnife4j
- public class SwaggerConfig {
- // 设置 openapi 基础参数
- @Bean
- public OpenAPI customOpenAPI() {
- return new OpenAPI()
- .info(new Info()
- .title("zxs API 管理")
- .version("1.0")
- .description("探索mybatis-flex与quartz demo")
- .license(new License().name("Apache 2.0")));
- }
- }
- package com.zxs.springbootmybatisflex.controller.client;
-
-
- import com.zxs.springbootmybatisflex.entity.JobVo;
- import com.zxs.springbootmybatisflex.entity.SysJob;
- import com.zxs.springbootmybatisflex.quartz.QuartzUtil;
- import com.zxs.springbootmybatisflex.service.SysJobService;
- import com.zxs.springbootmybatisflex.uitl.DataResult;
- import com.zxs.springbootmybatisflex.zenum.ActionEnum;
- import io.swagger.v3.oas.annotations.Operation;
- import io.swagger.v3.oas.annotations.tags.Tag;
- import jakarta.annotation.Resource;
- import org.springframework.util.ObjectUtils;
- import org.springframework.web.bind.annotation.*;
-
- import java.util.List;
-
- /**
- * 定时任务调度表(SysJob)表控制层
- *
- * @author makejava
- * @since 2023-10-19 09:17:58
- */
- @RestController
- @Tag(name = "任务中心")
- @RequestMapping("sysJob")
- public class SysJobController {
- /**
- * 服务对象
- */
- @Resource
- private SysJobService sysJobService;
-
-
-
-
- @Operation(summary = "获取任务列表", description = "获取任务列表")
- @PostMapping("/getJobList")
- public DataResult
<SysJob>> getJobList() {
- DataResult
<SysJob>> result = new DataResult<>();
- List<SysJob> list =sysJobService.list();
- result.setData(list);
- return result;
- }
-
- @Operation(summary = "根据主键获取任务信息")
- @PostMapping("/getJobById/{id}")
- public DataResult<SysJob> getJobById(@PathVariable(value = "id") Integer id) {
- DataResult<SysJob> result = new DataResult<>();
- result.setData(sysJobService.getById(id));
- return result;
- }
- @PostMapping("/saveJob")
- @Operation(summary="新增/修改任务",description="新增/修改任务,并加入的调度器中执行")
- public DataResult<Boolean> saveJob(SysJob sysJob) {
- DataResult<Boolean> result = new DataResult<>();
- result.setData(sysJobService.saveOrUpdate(sysJob));
- QuartzUtil.startJob(sysJob);
- return result;
- }
-
- @PostMapping("/deleteJob/{id}")
- @Operation(summary="删除任务",description="删除任务,并删除调度器中执行的该任务")
- public DataResult<Boolean> deleteJob(@PathVariable(value = "id") Integer id) {
- DataResult<Boolean> result = new DataResult<>();
- SysJob sysJob = sysJobService.getById(id);
- boolean data = this.sysJobService.removeById(id);
- result.setData(data);
- if(!ObjectUtils.isEmpty(sysJob)) {
- JobVo jobVo = new JobVo();
- jobVo.setJobId(sysJob.getJobId());
- jobVo.setJobGroup(sysJob.getJobGroup());
- QuartzUtil.doJob(jobVo, ActionEnum.delete);
- }
- return result;
- }
-
-
- @GetMapping("/getJobAndJoin/{id}")
- @Operation(summary="开启/关闭任务",description="获取一个任务,修改任务,并加入/丢出的调度器中执行")
- public DataResult<SysJob> getJobAndJoin(@PathVariable(value = "id") Integer id) {
- DataResult<SysJob> result = new DataResult<>();
- SysJob one = sysJobService.getById(id);
- if("0".equals(one.getStatus())){
- one.setStatus("1");
- }else{
- one.setStatus("0");
- }
- sysJobService.updateById(one);
- QuartzUtil.startJob(one);
- result.setData(one);
- return result;
- }
-
-
-
- @PostMapping("/runJob")
- @Operation(summary="手动执行任务",description="手动执行任务")
- public DataResult<Boolean> runJob(String invokeTarget) {
- DataResult<Boolean> result = new DataResult<>();
- QuartzUtil.runJob(invokeTarget);
- return result;
- }
-
-
-
- @PostMapping("/checkJob")
- @Operation(summary="检查任务",description="检测任务")
- public DataResult<Boolean> checkJob(JobVo jobVo) {
- DataResult<Boolean> result = new DataResult<>();
- QuartzUtil.doJob(jobVo,ActionEnum.check);
- return result;
- }
-
- @PostMapping("/resumeJob")
- @Operation(summary="恢复任务",description="恢复任务")
- public DataResult<Boolean> resumeJob(JobVo sysJob) {
- DataResult<Boolean> result = new DataResult<>();
- QuartzUtil.doJob(sysJob,ActionEnum.resume);
- return result;
- }
-
- @PostMapping("/pauseJob")
- @Operation(summary="暂停任务",description="暂停任务")
- public DataResult<Boolean> pauseJob(JobVo sysJob) {
- DataResult<Boolean> result = new DataResult<>();
- QuartzUtil.doJob(sysJob,ActionEnum.pause);
- return result;
- }
-
- }
-
- package com.zxs.springbootmybatisflex.dao;
-
-
- import com.mybatisflex.core.BaseMapper;
- import com.zxs.springbootmybatisflex.entity.SysJob;
- import org.apache.ibatis.annotations.Mapper;
-
- /**
- * 定时任务调度表(SysJob)表数据库访问层
- *
- * @author makejava
- * @since 2023-10-19 09:17:58
- */
- @Mapper
- public interface SysJobDao extends BaseMapper<SysJob> {
-
- }
-
- package com.zxs.springbootmybatisflex.entity;
-
- import lombok.Data;
-
- import java.io.Serializable;
-
- @Data
- public class JobVo implements Serializable {
- private Integer jobId;
- private String jobGroup;
- }
- package com.zxs.springbootmybatisflex.entity;
-
-
- import com.fasterxml.jackson.annotation.JsonFormat;
- import com.mybatisflex.annotation.Id;
- import com.mybatisflex.annotation.KeyType;
- import com.mybatisflex.annotation.Table;
- import com.mybatisflex.core.activerecord.Model;
- import io.swagger.v3.oas.annotations.media.Schema;
- import lombok.Data;
-
- import java.util.Date;
-
- /**
- * 定时任务调度表(SysJob)表实体类
- *
- * @author makejava
- * @since 2023-10-19 09:17:59
- */
- @Data
- @Schema(description="定时任务调度表")
- @Table("sys_job")
- public class SysJob extends Model<SysJob> {
-
- @Schema(description="任务ID")
- @Id(keyType = KeyType.Auto)
- private Integer jobId;
-
-
- @Schema(description="任务名称")
- private String jobName;
-
-
- @Schema(description="任务组名")
- private String jobGroup;
-
-
- @Schema(description="调用目标字符串")
- private String invokeTarget;
-
-
- @Schema(description="cron执行表达式")
- private String cronExpression;
-
-
- @Schema(description="计划执行错误策略(1立即执行 2执行一次 3放弃执行)")
- private String misfirePolicy;
-
-
- @Schema(description="是否并发执行(0允许 1禁止)")
- private String concurrent;
-
-
- @Schema(description="状态(0正常 1暂停)")
- private String status;
-
-
- @Schema(description="创建者")
- private String createBy;
-
-
- @Schema(description="创建时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date createTime;
-
-
- @Schema(description="更新者")
- private String updateBy;
-
-
- @Schema(description="更新时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date updateTime;
-
-
- @Schema(description="备注信息")
- private String remark;
-
-
- @Schema(description="0-正常,1-删除")
- private Integer deleteStatus;
-
- }
-
- package com.zxs.springbootmybatisflex.exception.code;
-
-
- public enum BaseResponseCode implements ResponseCodeInterface {
- /**
- * 这个要和前段约定好
- * 引导用户去登录界面的
- * code=401001 引导用户重新登录
- * code=401002 token 过期刷新token
- * code=401008 无权限访问
- */
- SUCCESS(200,"操作成功"),
- SYSTEM_BUSY(500001, "系统繁忙,请稍候再试"),
- OPERATION_ERRO(500002,"操作失败"),
- METHODARGUMENTNOTVALIDEXCEPTION(500003, "方法参数校验异常"),
- ;
-
- /**
- * 错误码
- */
- private final int code;
- /**
- * 错误消息
- */
- private final String msg;
-
- BaseResponseCode(int code, String msg) {
- this.code = code;
- this.msg = msg;
- }
-
- @Override
- public int getCode() {
- return code;
- }
-
- @Override
- public String getMsg() {
- return msg;
- }
- }
- package com.zxs.springbootmybatisflex.exception.code;
-
-
- public interface ResponseCodeInterface {
- int getCode();
-
- String getMsg();
- }
- package com.zxs.springbootmybatisflex.exception.handler;
-
-
- import com.zxs.springbootmybatisflex.exception.BusinessException;
- import com.zxs.springbootmybatisflex.exception.code.BaseResponseCode;
- import com.zxs.springbootmybatisflex.uitl.DataResult;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.validation.ObjectError;
- import org.springframework.web.bind.MethodArgumentNotValidException;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.RestControllerAdvice;
-
- import java.util.List;
-
-
- @RestControllerAdvice
- @Slf4j
- public class RestExceptionHandler {
-
-
- @ExceptionHandler(Exception.class)
- public <T> DataResult<T> handleException(Exception e){
- log.error("Exception,exception:{}", e);
- return DataResult.getResult(BaseResponseCode.SYSTEM_BUSY);
- }
-
-
- @ExceptionHandler(value = BusinessException.class)
- <T> DataResult<T> businessExceptionHandler(BusinessException e) {
- log.error("BusinessException,exception:{}", e);
- return new DataResult<>(e.getMessageCode(),e.getDetailMessage());
- }
-
-
- @ExceptionHandler(MethodArgumentNotValidException.class)
- <T> DataResult<T> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
- log.error("methodArgumentNotValidExceptionHandler bindingResult.allErrors():{},exception:{}", e.getBindingResult().getAllErrors(), e);
- List<ObjectError> errors = e.getBindingResult().getAllErrors();
- return createValidExceptionResp(errors);
- }
- private <T> DataResult<T> createValidExceptionResp(List<ObjectError> errors) {
- String[] msgs = new String[errors.size()];
- int i = 0;
- for (ObjectError error : errors) {
- msgs[i] = error.getDefaultMessage();
- log.info("msg={}",msgs[i]);
- i++;
- }
- return DataResult.getResult(BaseResponseCode.METHODARGUMENTNOTVALIDEXCEPTION.getCode(), msgs[0]);
- }
- }
- package com.zxs.springbootmybatisflex.exception;
-
-
- import com.zxs.springbootmybatisflex.exception.code.ResponseCodeInterface;
-
- public class BusinessException extends RuntimeException{
- /**
- * 异常编号
- */
- private final int messageCode;
-
- /**
- * 对messageCode 异常信息进行补充说明
- */
- private final String detailMessage;
-
- public BusinessException(int messageCode,String message) {
- super(message);
- this.messageCode = messageCode;
- this.detailMessage = message;
- }
- /**
- * 构造函数
- * @param code 异常码
- */
- public BusinessException(ResponseCodeInterface code) {
- this(code.getCode(), code.getMsg());
- }
-
- public int getMessageCode() {
- return messageCode;
- }
-
- public String getDetailMessage() {
- return detailMessage;
- }
- }
- package com.zxs.springbootmybatisflex.exception;
-
-
- import com.zxs.springbootmybatisflex.exception.code.ResponseCodeInterface;
-
- public class RoleSaveException extends RuntimeException{
- /**
- * 异常编号
- */
- private final int messageCode;
-
- /**
- * 对messageCode 异常信息进行补充说明
- */
- private final String detailMessage;
-
- public RoleSaveException(int messageCode, String message) {
- super(message);
- this.messageCode = messageCode;
- this.detailMessage = message;
- }
- /**
- * 构造函数
- * @param code 异常码
- */
- public RoleSaveException(ResponseCodeInterface code) {
- this(code.getCode(), code.getMsg());
- }
-
- public int getMessageCode() {
- return messageCode;
- }
-
- public String getDetailMessage() {
- return detailMessage;
- }
- }
- package com.zxs.springbootmybatisflex.quartz.task;
-
- import org.springframework.stereotype.Service;
-
- @Service("task")
- public class DoTask {
- public void sout() {
- System.out.println("我是干输出的");
- }
- public void ceshi() {
- System.out.println("我是干测试的");
- }
- public void buzhidao() {
- System.out.println("我不知道干啥的");
- }
- public void dajiangyou() {
- System.out.println("我是打酱油的");
- }
- public void chuiniu() {
- System.out.println("我是吹牛的");
- }
-
- public void maren() {
- System.out.println("我是骂人的");
- }
- public void duiren() {
- System.out.println("我是怼人的");
- }
- public void yaofan() {
- System.out.println("我是要饭的");
- }
- public void chifan() {
- System.out.println("我是吃饭的");
- }
- }
- package com.zxs.springbootmybatisflex.service.impl;
-
- import com.mybatisflex.spring.service.impl.ServiceImpl;
- import com.zxs.springbootmybatisflex.dao.SysJobDao;
- import com.zxs.springbootmybatisflex.entity.SysJob;
- import com.zxs.springbootmybatisflex.service.SysJobService;
- import org.springframework.stereotype.Service;
-
- /**
- * 定时任务调度表(SysJob)表服务实现类
- *
- * @author makejava
- * @since 2023-10-19 09:17:59
- */
- @Service
- public class SysJobServiceImpl extends ServiceImpl
implements SysJobService { -
-
- }
-
- package com.zxs.springbootmybatisflex.service;
-
- import com.mybatisflex.core.service.IService;
- import com.zxs.springbootmybatisflex.entity.SysJob;
-
- /**
- * 定时任务调度表(SysJob)表服务接口
- *
- * @author makejava
- * @since 2023-10-19 09:17:59
- */
- public interface SysJobService extends IService<SysJob> {
-
- }
-
- package com.zxs.springbootmybatisflex.uitl;
-
- import com.zxs.springbootmybatisflex.exception.code.BaseResponseCode;
- import com.zxs.springbootmybatisflex.exception.code.ResponseCodeInterface;
- import lombok.Data;
-
-
- @Data
- public class DataResult<T>{
-
- /**
- * 请求响应code,0为成功 其他为失败
- */
- private int code;
-
- /**
- * 响应异常码详细信息
- */
- private String msg;
-
- /**
- * 响应内容 , code 0 时为 返回 数据
- */
- private T data;
-
- public DataResult(int code, T data) {
- this.code = code;
- this.data = data;
- this.msg=null;
- }
-
- public DataResult(int code, String msg, T data) {
- this.code = code;
- this.msg = msg;
- this.data = data;
- }
-
- public DataResult(int code, String msg) {
- this.code = code;
- this.msg = msg;
- this.data=null;
- }
-
-
- public DataResult() {
- this.code= BaseResponseCode.SUCCESS.getCode();
- this.msg=BaseResponseCode.SUCCESS.getMsg();
- this.data=null;
- }
-
- public DataResult(T data) {
- this.data = data;
- this.code=BaseResponseCode.SUCCESS.getCode();
- this.msg=BaseResponseCode.SUCCESS.getMsg();
- }
-
- public DataResult(ResponseCodeInterface responseCodeInterface) {
- this.data = null;
- this.code = responseCodeInterface.getCode();
- this.msg = responseCodeInterface.getMsg();
- }
-
- public DataResult(ResponseCodeInterface responseCodeInterface, T data) {
- this.data = data;
- this.code = responseCodeInterface.getCode();
- this.msg = responseCodeInterface.getMsg();
- }
-
- public static <T>DataResult success(){
- return new <T>DataResult();
- }
-
- public static <T>DataResult success(T data){
- return new <T>DataResult(data);
- }
-
- public static <T>DataResult getResult(int code,String msg,T data){
- return new <T>DataResult(code,msg,data);
- }
-
- public static <T>DataResult getResult(int code,String msg){
- return new <T>DataResult(code,msg);
- }
-
- public static <T>DataResult getResult(BaseResponseCode responseCode){
- return new <T>DataResult(responseCode);
- }
-
- public static <T>DataResult getResult(BaseResponseCode responseCode,T data){
-
- return new <T>DataResult(responseCode,data);
- }
- }
- package com.zxs.springbootmybatisflex.uitl;
-
- import org.apache.commons.lang3.Validate;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.DisposableBean;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.stereotype.Component;
-
- @Component
- public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
-
- private static ApplicationContext applicationContext = null;
-
- private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
-
- /**
- * 取得存储在静态变量中的ApplicationContext.
- */
- public static ApplicationContext getApplicationContext() {
- assertContextInjected();
- return applicationContext;
- }
-
- /**
- * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
- */
- @SuppressWarnings("unchecked")
- public static <T> T getBean(String name) {
- assertContextInjected();
- return (T) applicationContext.getBean(name);
- }
-
- /**
- * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
- */
- public static <T> T getBean(Class<T> requiredType) {
- assertContextInjected();
- return applicationContext.getBean(requiredType);
- }
-
- /**
- * 清除SpringContextHolder中的ApplicationContext为Null.
- */
- public static void clearHolder() {
- logger.debug("清除SpringContextHolder中的ApplicationContext:"
- + applicationContext);
- applicationContext = null;
- }
-
- /**
- * 实现ApplicationContextAware接口, 注入Context到静态变量中.
- */
- @Override
- public void setApplicationContext(ApplicationContext applicationContext)throws BeansException {
- // logger.debug("注入ApplicationContext到SpringContextHolder:{}", applicationContext);
-
- if (SpringContextHolder.applicationContext != null) {
- logger.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
- }
-
- SpringContextHolder.applicationContext = applicationContext; // NOSONAR
- }
-
- /**
- * 实现DisposableBean接口, 在Context关闭时清理静态变量.
- */
- @Override
- public void destroy() throws Exception {
- SpringContextHolder.clearHolder();
- }
-
- /**
- * 检查ApplicationContext不为空.
- */
- private static void assertContextInjected() {
- Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
- }
- }
- package com.zxs.springbootmybatisflex.zenum;
-
-
- public interface ActionEnum {
- String pause="pause";
- String resume="resume";
- String check="check";
- String delete="delete";
- String start="start";
- }
- package com.zxs.springbootmybatisflex.zenum;
-
-
- public enum JobEnum implements JobInterface {
-
- Key("jobkey"),
- MISFIRE_DEFAULT("0"),
- MISFIRE_IGNORE("1"),
- MISFIRE_FIRE_AND_PROCEED("2"),
- MISFIRE_DO_NOTHING("3"),
- PAUSE("1"),
- ;
-
-
- private final String code;
-
-
- JobEnum(String code) {
- this.code = code;
- }
-
- @Override
- public String getCode() {
- return code;
- }
-
- }
- package com.zxs.springbootmybatisflex.zenum;
-
-
- public interface JobInterface {
- String getCode();
- }
- package com.zxs.springbootmybatisflex;
-
- import org.mybatis.spring.annotation.MapperScan;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
-
- @SpringBootApplication
- @MapperScan("com.zxs.springbootmybatisflex.dao")
- public class SpringbootMybatisFlexApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(SpringbootMybatisFlexApplication.class, args);
- }
-
-
- }
- "1.0" encoding="UTF-8"?>
- mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.zxs.springbootmybatisflex.dao.SysJobDao">
-
- <resultMap type="com.zxs.springbootmybatisflex.entity.SysJob" id="SysJobMap">
- <result property="jobId" column="job_id" jdbcType="INTEGER"/>
- <result property="jobName" column="job_name" jdbcType="VARCHAR"/>
- <result property="jobGroup" column="job_group" jdbcType="VARCHAR"/>
- <result property="invokeTarget" column="invoke_target" jdbcType="VARCHAR"/>
- <result property="cronExpression" column="cron_expression" jdbcType="VARCHAR"/>
- <result property="misfirePolicy" column="misfire_policy" jdbcType="VARCHAR"/>
- <result property="concurrent" column="concurrent" jdbcType="VARCHAR"/>
- <result property="status" column="status" jdbcType="VARCHAR"/>
- <result property="createBy" column="create_by" jdbcType="VARCHAR"/>
- <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
- <result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
- <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
- <result property="remark" column="remark" jdbcType="VARCHAR"/>
- <result property="deleteStatus" column="delete_status" jdbcType="INTEGER"/>
- resultMap>
-
-
- mapper>
-


-
- DROP TABLE IF EXISTS `sys_job`;
- CREATE TABLE `sys_job` (
- `job_id` int(6) NOT NULL AUTO_INCREMENT COMMENT '任务ID',
- `job_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '任务名称',
- `job_group` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'DEFAULT' COMMENT '任务组名',
- `invoke_target` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '调用目标字符串',
- `cron_expression` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT 'cron执行表达式',
- `misfire_policy` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '3' COMMENT '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
- `concurrent` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '是否并发执行(0允许 1禁止)',
- `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1暂停)',
- `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者',
- `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
- `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者',
- `update_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间',
- `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '备注信息',
- `delete_status` int(1) NOT NULL DEFAULT 0 COMMENT '0-正常,1-删除',
- PRIMARY KEY (`job_id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '定时任务调度表' ROW_FORMAT = Dynamic;
-
- -- ----------------------------
- -- Records of sys_job
- -- ----------------------------
- INSERT INTO `sys_job` VALUES (1, '输出任务', 'DEFAULT', 'task.sout', '0/3 * * * * ?', '3', '0', '0', 'admin', '2023-06-09 11:27:28', 'zxs', '2023-10-19 10:51:17', '', 0);
- INSERT INTO `sys_job` VALUES (2, '测试任务', 'DEFAULT', 'task.ceshi', '0/4 * * * * ?', '3', '0', '1', '', NULL, 'zxs', '2023-10-18 16:28:02', '', 0);
- INSERT INTO `sys_job` VALUES (3, '我不知道干啥的', 'DEFAULT', 'task.buzhidao', '0/5 * * * * ?', '3', '0', '1', 'zxs', '2023-10-18 14:48:40', '', '2023-10-18 16:28:04', '', 0);
- INSERT INTO `sys_job` VALUES (4, '打酱油', 'DEFAULT', 'task.dajiangyou', '0/6 * * * * ?', '3', '0', '1', 'zxs', '2023-10-18 14:49:20', 'zxs', '2023-10-18 16:28:06', '', 0);
- INSERT INTO `sys_job` VALUES (5, '吹牛', 'DEFAULT', 'task.chuiniu', '0/7 * * * * ?', '3', '0', '1', 'zxs', '2023-10-18 14:50:53', '', '2023-10-18 16:28:07', '', 0);
- INSERT INTO `sys_job` VALUES (6, '骂人', 'DEFAULT', 'task.maren', '0/8 * * * * ?', '3', '0', '1', 'zxs', '2023-10-18 14:51:28', '', '2023-10-18 16:28:09', '', 0);
- INSERT INTO `sys_job` VALUES (7, '怼人的', 'DEFAULT', 'task.duiren', '0/4 * * * * ?', '3', '0', '1', 'zxs', '2023-10-18 15:22:34', '', '2023-10-18 16:28:10', '', 0);
- INSERT INTO `sys_job` VALUES (8, '要饭的', 'DEFAULT', 'task.yaofan', '0/5 * * * * ?', '3', '0', '1', 'zxs', '2023-10-18 15:23:38', '', '2023-10-18 16:28:12', '', 0);
- INSERT INTO `sys_job` VALUES (9, '吃饭的', 'DEFAULT', 'task.chifan', '0/6 * * * * ?', '3', '0', '1', 'zxs', '2023-10-18 15:24:08', 'zxs', '2023-10-18 16:28:15', '哈哈哈哈0', 0);
-
- SET FOREIGN_KEY_CHECKS = 1;
以上就是一个完整的demo了
运行之后访问http://127.0.0.1:8080/doc.html

可以看到我们开放的api
执行以上的sql,有可以看到我内置的一些拿来测试的任务

然后我随便找一个任务开启

当任务状态为0的时候,该任务就是正常的运行中的状态
当然你也可以控制一下,当服务关闭时,去把所有为0状态重置为1,把任务关闭掉,或者当服务重启时,去初始化把状态为0的任务加入执行器中,不然每次重启,任务都不在执行器中与数据库的状态不一致
例如:
- @PreDestroy
- public void stop() {
- stopTask();
- }
- public void stopTask() {
- List<SysJob> jobs = sysJobService.list().stream()
- .map(s -> {
- s.setStatus("1");
- return s;
- })
- .collect(Collectors.toList());
- sysJobService.saveOrUpdateBatch(jobs);
- }
