精华内容
下载资源
问答
  • springboot整合quartz定时任务
    2021-08-11 16:21:25

    pom.xml

    <!-- SpringBoot 整合 Quartz 定时任务 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-quartz</artifactId>
                <version>2.3.5.RELEASE</version>
            </dependency>
    

    sql

    DROP TABLE IF EXISTS `scheduled_task`;
    CREATE TABLE `scheduled_task` (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
      `taskkey` varchar(128) DEFAULT NULL COMMENT '任务key值(使用bean名称)',
      `taskdesc` varchar(128) DEFAULT NULL COMMENT '任务描述',
      `taskcron` varchar(128) DEFAULT NULL COMMENT '任务表达式',
      `initstartflag` int(1) DEFAULT '1' COMMENT '程序初始化是否启动 1 是 0 否',
      `createtime` varchar(30) DEFAULT NULL COMMENT '创建时间',
      `createuser` varchar(15) DEFAULT NULL COMMENT '创建工作人员',
      `createuserid` int(6) DEFAULT NULL COMMENT '创建人员id',
      `del` int(1) DEFAULT NULL COMMENT '是否删除',
      `updateuser` varchar(15) DEFAULT NULL COMMENT '修改人员',
      `updateuserid` int(6) DEFAULT NULL COMMENT '修改人员id',
      `updatetime` varchar(30) DEFAULT NULL COMMENT '修改时间',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='定时任务表';
    

    ScheduledTaskConfig

    import com.xnhy.educationadmin.controller.schedule.ScheduledTaskJob;
    import com.xnhy.educationadmin.pojo.ScheduledTaskEnum;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
    
    import java.util.Map;
    
    @Configuration
    public class ScheduledTaskConfig {
    
        /**
         * 日志
         */
        private static final Logger LOGGER = LogManager.getLogger(ScheduledTaskConfig.class);
    
        @Bean
        public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
            LOGGER.info("创建定时任务调度线程池 start");
            ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
            threadPoolTaskScheduler.setPoolSize(20);
            threadPoolTaskScheduler.setThreadNamePrefix("taskExecutor-");
            threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
            threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
            LOGGER.info("创建定时任务调度线程池 end");
            return threadPoolTaskScheduler;
        }
    
        /**
         * 初始化定时任务Map
         * key :任务key
         * value : 执行接口实现
         */
        @Bean(name = "scheduledTaskJobMap")
        public Map<String, ScheduledTaskJob> scheduledTaskJobMap() {
            return ScheduledTaskEnum.initScheduledTask();
        }
    }
    
    

    enum

    import com.xnhy.educationadmin.controller.schedule.OperationScheduleTask;
    import com.xnhy.educationadmin.controller.schedule.ScheduledTask01;
    import com.xnhy.educationadmin.controller.schedule.ScheduledTaskJob;
    import com.xnhy.educationadmin.controller.schedule.VideoCompressPathTask;
    import com.xnhy.educationadmin.controller.search.AlbumSearchTask;
    import com.xnhy.educationadmin.controller.search.ContentSearchTask;
    
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 定时任务枚举
     * 2021-08-07
     * >>> 2021-08-09 chen
     */
    public enum ScheduledTaskEnum {
        /**
         * 运营位定时任务
         * 2021-08-09
         * chenchao
         */
        TASK_01("OperationScheduleTask", new OperationScheduleTask()),
        // 测试定时任务
        TASK_02("scheduledTask01", new ScheduledTask01()),
        /**
         * 视频压缩路径定时任务
         * 2021-08-09
         * chenchao
         */
        TASK_03("VideoCompressPathTask", new VideoCompressPathTask()),
        // elasticsearch 数据同步 专辑数据
        TASK_04("AlbumSearchTask", new AlbumSearchTask()),
        // elasticsearch 数据同步 单集数据
        TASK_05("ContentSearchTask", new ContentSearchTask()),
        ;// 定义的值,如果有新的定时任务需要添加值 chenchao 2021-08-09
        /**
         * 定时任务key
         */
        private String taskKey;
        /**
         * 定时任务 执行实现类
         */
        private ScheduledTaskJob scheduledTaskJob;
    
        ScheduledTaskEnum(String taskKey, ScheduledTaskJob scheduledTaskJob) {
            this.taskKey = taskKey;
            this.scheduledTaskJob = scheduledTaskJob;
        }
    
        /**
         * 初始化 所有任务
         */
        public static Map<String, ScheduledTaskJob> initScheduledTask() {
            if (ScheduledTaskEnum.values().length < 0) {
                return new ConcurrentHashMap<>();
            }
            Map<String, ScheduledTaskJob> scheduledTaskJobMap = new ConcurrentHashMap<>();
            for (ScheduledTaskEnum taskEnum : ScheduledTaskEnum.values()) {
                scheduledTaskJobMap.put(taskEnum.taskKey, taskEnum.scheduledTaskJob);
            }
            return scheduledTaskJobMap;
        }
    }
    
    

    ScheduledTaskJob

    /**
     * 调度任务公共父接口
     */
    public interface ScheduledTaskJob extends Runnable {
    }
    
    

    ScheduledTask01

    package com.xnhy.educationadmin.controller.schedule;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    /**
     * 任务 01
     */
    public class ScheduledTask01 implements ScheduledTaskJob {
        /**
         * 日志
         */
        private static final Logger LOGGER = LogManager.getLogger(ScheduledTask01.class);
    
        @Override
        public void run() {
            LOGGER.info("ScheduledTask => 01  run  当前线程名称 {} ", Thread.currentThread().getName());
        }
    }
    
    

    controller

    import com.alibaba.fastjson.JSONObject;
    import com.xnhy.educationadmin.domain.common.ScheduledTaskVO;
    import com.xnhy.educationadmin.service.schedule.ScheduledTaskService;
    import com.xnhy.educationadmin.util.AjaxJson;
    import com.xnhy.educationadmin.util.Util;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * 定时任务 controller
     */
    @RestController
    @RequestMapping("/scheduled")
    public class ScheduledController {
    
    
        @Autowired
        private ScheduledTaskService scheduledTaskService;
        /**
         * 所有任务列表
         */
        @RequestMapping("/taskList")
        public Object taskList(ScheduledTaskVO vo, HttpServletRequest request) {
            AjaxJson json = new AjaxJson();
            try {
                if (!Util.isEmpty(vo.getPage())){
                    vo.setPage((vo.getPage() - 1)*vo.getLimit());
                }
                // 管理页面搜索功能
                String search = request.getParameter("searchParams");
                if (!Util.isEmpty(search)){
                    JSONObject jsonObject = JSONObject.parseObject(search);
                    vo.setTaskdesc(Util.toSearchObject(jsonObject,"title"));
                }
                json.setCode(0);
                json.setCount(scheduledTaskService.countScheduledTask(vo));
                json.setData(scheduledTaskService.listScheduledTask(vo));
            }catch (Exception e){
                json.setCode(1);
                json.setMsg(e.toString());
                e.printStackTrace();
            }
            return json;
        }
    
        /**
         * 根据任务key => 启动任务
         */
        @RequestMapping("/start")
        public Object start(@RequestParam("taskKey") String taskKey) {
            AjaxJson json= new AjaxJson();
            try {
                scheduledTaskService.start(taskKey);
                json.setCode(0);
                json.setMsg("开启成功");
            }catch (Exception e){
                json.setCode(1);
                json.setMsg(e.toString());
                e.printStackTrace();
            }
            return json;
        }
    
        /**
         * 根据任务key => 停止任务
         */
        @RequestMapping("/stop")
        public Object stop(@RequestParam("taskKey") String taskKey) {
            AjaxJson json= new AjaxJson();
            try {
                scheduledTaskService.stop(taskKey);
                json.setCode(0);
                json.setMsg("关闭成功");
            }catch (Exception e){
                json.setCode(1);
                json.setMsg(e.toString());
                e.printStackTrace();
            }
            return json;
        }
    
        /**
         * 根据任务key => 重启任务
         */
        @RequestMapping("/restart")
        public String restart(@RequestParam("taskKey") String taskKey) {
            scheduledTaskService.restart(taskKey);
            return "restart success";
        }
    
        /**
         * 添加详情
         * @param request
         * @param vo
         * @return
         */
        @RequestMapping("/addDetail")
        public Object addDetail(HttpServletRequest request,ScheduledTaskVO vo){
            AjaxJson json = new AjaxJson();
            try {
                String username =request.getSession().getAttribute("username").toString();
                String  userId = request.getSession().getAttribute("userid").toString();
                vo.setCreatetime(Util.getNow(null));
                vo.setCreateuser(username);
                vo.setCreateuserid(Integer.parseInt(userId));
                vo.setDel(1);
                scheduledTaskService.insertSelective(vo);
                json.setMsg("请求成功");
                json.setCode(0);
            }catch (Exception e){
                json.setMsg(e.toString());
                json.setCode(1);
                e.printStackTrace();
            }
            return json;
        }
    
        /**
         * 修改
         * @param request
         * @param vo
         * @return
         */
        @RequestMapping("/updateDetail")
        public Object updateDetail(HttpServletRequest request,ScheduledTaskVO vo){
            AjaxJson json = new AjaxJson();
            try {
                String username =request.getSession().getAttribute("username").toString();
                String  userId = request.getSession().getAttribute("userid").toString();
                vo.setUpdatetime(Util.getNow(null));
                vo.setUpdateuser(username);
                vo.setUpdateuserid(Integer.parseInt(userId));
                vo.setDel(1);
                scheduledTaskService.updateByPrimaryKeySelective(vo);
                json.setMsg("修改成功");
                json.setCode(0);
            }catch (Exception e){
                json.setMsg(e.toString());
                json.setCode(1);
                e.printStackTrace();
            }
            return json;
        }
    
        @RequestMapping("/remove")
        public Object remove(@RequestParam(value = "id", required = false, defaultValue = "")String id){
            AjaxJson json = new AjaxJson();
            try {
                String[] str = id.split(",");
                for (int i = 0;i<str.length;i++) {
                    scheduledTaskService.deleteByPrimaryKey(Integer.parseInt(str[i]));
                }
                json.setCode(0);
                json.setMsg("删除成功");
            }catch (Exception e){
                json.setCode(1);
                json.setMsg(e.toString());
                e.printStackTrace();
            }
            return json;
        }
    }
    

    service

    package com.xnhy.educationadmin.service.schedule;
    
    import com.xnhy.educationadmin.domain.common.ScheduledTaskVO;
    
    import java.util.List;
    
    public interface ScheduledTaskService {
        /**
         * 所有任务列表
         */
        List<ScheduledTaskVO> taskList();
    
        /**
         * 根据任务key 启动任务
         */
        Boolean start(String taskKey);
    
        /**
         * 根据任务key 停止任务
         */
        Boolean stop(String taskKey);
    
        /**
         * 根据任务key 重启任务
         */
        Boolean restart(String taskKey);
    
    
        /**
         * 程序启动时初始化  ==> 启动所有正常状态的任务
         */
        void initAllTask(List<ScheduledTaskVO> scheduledTaskBeanList);
    
        /**
         * 数据列表
         * @param record
         * @return
         */
        List<ScheduledTaskVO> listScheduledTask(ScheduledTaskVO record);
    
        /**
         * 总数
         * @param record
         * @return
         */
        long countScheduledTask(ScheduledTaskVO record);
    
        /**
         * This method was generated by MyBatis Generator.
         * This method corresponds to the database table bj_xnhy_scheduled_task
         *
         * @mbg.generated
         */
        int insertSelective(ScheduledTaskVO record);
    
        /**
         * This method was generated by MyBatis Generator.
         * This method corresponds to the database table bj_xnhy_scheduled_task
         *
         * @mbg.generated
         */
        ScheduledTaskVO selectByPrimaryKey(Integer id);
    
        /**
         * This method was generated by MyBatis Generator.
         * This method corresponds to the database table bj_xnhy_scheduled_task
         *
         * @mbg.generated
         */
        int updateByPrimaryKeySelective(ScheduledTaskVO record);
    
        /**
         * 删除
         * @param id
         * @return
         */
        int deleteByPrimaryKey(Integer id);
    
    }
    
    

    serviceImpl

    import com.xnhy.educationadmin.controller.schedule.ScheduledTaskJob;
    import com.xnhy.educationadmin.dao.common.ScheduledTaskMapper;
    import com.xnhy.educationadmin.domain.common.ScheduledTaskVO;
    import com.xnhy.educationadmin.service.schedule.ScheduledTaskService;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.scheduling.Trigger;
    import org.springframework.scheduling.TriggerContext;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
    import org.springframework.scheduling.support.CronTrigger;
    import org.springframework.stereotype.Service;
    import org.springframework.util.CollectionUtils;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ScheduledFuture;
    import java.util.concurrent.locks.ReentrantLock;
    
    @Service
    public class ScheduledTaskServiceImpl implements ScheduledTaskService {
    
        private static final Logger LOGGER = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    
        @Autowired
        private ScheduledTaskMapper taskMapper;// 修改成自己的mapper
        /**
         * 可重入锁
         */
        private ReentrantLock lock = new ReentrantLock();
        /**
         * 定时任务线程池
         */
        @Autowired
        private ThreadPoolTaskScheduler threadPoolTaskScheduler;
        /**
         * 所有定时任务存放Map
         * key :任务 key
         * value:任务实现
         */
        @Autowired
        @Qualifier(value = "scheduledTaskJobMap")
        private Map<String, ScheduledTaskJob> scheduledTaskJobMap;
    
        /**
         * 存放已经启动的任务map
         */
        private Map<String, ScheduledFuture> scheduledFutureMap = new ConcurrentHashMap<>();
    
        /**
         * 所有任务列表
         */
        @Override
        public List<ScheduledTaskVO> taskList() {
            LOGGER.info(">>>>>> 获取任务列表开始 >>>>>> ");
            //数据库查询所有任务 => 未做分页
            List<ScheduledTaskVO> taskBeanList = taskMapper.getAllTask();
            if (CollectionUtils.isEmpty(taskBeanList)) {
                return new ArrayList<>();
            }
    
            for (ScheduledTaskVO taskBean : taskBeanList) {
                String taskKey = taskBean.getTaskkey();
                //是否启动标记处理
                taskBean.setStartFlag(this.isStart(taskKey));
            }
            LOGGER.info(">>>>>> 获取任务列表结束 >>>>>> ");
            return taskBeanList;
        }
    
    
        /**
         * 根据任务key 启动任务
         */
        @Override
        public Boolean start(String taskKey) {
            LOGGER.info(">>>>>> 启动任务 {} 开始 >>>>>>"+taskKey);
            //添加锁放一个线程启动,防止多人启动多次
            lock.lock();
            LOGGER.info(">>>>>> 添加任务启动锁完毕");
            try {
                //校验是否已经启动
                if (this.isStart(taskKey)) {
                    LOGGER.info(">>>>>> 当前任务已经启动,无需重复启动!");
                    return false;
                }
                //校验任务是否存在
                if (!scheduledTaskJobMap.containsKey(taskKey)) {
                    return false;
                }
                //根据key数据库获取任务配置信息
                ScheduledTaskVO scheduledTask = taskMapper.getByKey(taskKey);
                //启动任务
                this.doStartTask(scheduledTask);
            } finally {
                // 释放锁
                lock.unlock();
                LOGGER.info(">>>>>> 释放任务启动锁完毕");
            }
           LOGGER.info(">>>>>> 启动任务 {} 结束 >>>>>>"+taskKey);
            return true;
        }
    
        /**
         * 根据 key 停止任务
         */
        @Override
        public Boolean stop(String taskKey) {
            LOGGER.info(">>>>>> 进入停止任务 {}  >>>>>>"+ taskKey);
            //当前任务实例是否存在
            boolean taskStartFlag = scheduledFutureMap.containsKey(taskKey);
            //LOGGER.info(">>>>>> 当前任务实例是否存在 {}", taskStartFlag);
            if (taskStartFlag) {
                //获取任务实例
                ScheduledFuture scheduledFuture = scheduledFutureMap.get(taskKey);
                //关闭实例
                scheduledFuture.cancel(true);
            }
            LOGGER.info(">>>>>> 结束停止任务 {}  >>>>>>"+ taskKey);
            return taskStartFlag;
        }
    
        /**
         * 根据任务key 重启任务
         */
        @Override
        public Boolean restart(String taskKey) {
            LOGGER.info(">>>>>> 进入重启任务 {}  >>>>>>"+ taskKey);
            //先停止
            this.stop(taskKey);
            //再启动
            return this.start(taskKey);
        }
    
        /**
         * 程序启动时初始化  ==> 启动所有正常状态的任务
         */
        @Override
        public void initAllTask(List<ScheduledTaskVO> scheduledTaskBeanList) {
            LOGGER.info("程序启动 ==> 初始化所有任务开始 !size={}"+ scheduledTaskBeanList.size());
            if (CollectionUtils.isEmpty(scheduledTaskBeanList)) {
                return;
            }
            for (ScheduledTaskVO scheduledTask : scheduledTaskBeanList) {
                //任务 key
                String taskKey = scheduledTask.getTaskkey();
                //校验是否已经启动
                if (this.isStart(taskKey)) {
                    continue;
                }
                //启动任务
                this.doStartTask(scheduledTask);
            }
            LOGGER.info("程序启动 ==> 初始化所有任务结束 !size={}"+scheduledTaskBeanList.size());
        }
    
        @Override
        public List<ScheduledTaskVO> listScheduledTask(ScheduledTaskVO record) {
            LOGGER.info(">>>>>> 获取任务列表开始 >>>>>> ");
            //数据库查询所有任务 => 未做分页
            List<ScheduledTaskVO> taskBeanList = taskMapper.listScheduledTask(record);
            if (CollectionUtils.isEmpty(taskBeanList)) {
                return new ArrayList<>();
            }
    
            for (ScheduledTaskVO taskBean : taskBeanList) {
                String taskKey = taskBean.getTaskkey();
                //是否启动标记处理
                taskBean.setStartFlag(this.isStart(taskKey));
            }
            LOGGER.info(">>>>>> 获取任务列表结束 >>>>>> ");
            return taskBeanList;
        }
    
        @Override
        public long countScheduledTask(ScheduledTaskVO record) {
            return taskMapper.countScheduledTask(record);
        }
    
        @Override
        public int insertSelective(ScheduledTaskVO record) {
            return taskMapper.insertSelective(record);
        }
    
        @Override
        public ScheduledTaskVO selectByPrimaryKey(Integer id) {
            return taskMapper.selectByPrimaryKey(id);
        }
    
        @Override
        public int updateByPrimaryKeySelective(ScheduledTaskVO record) {
            return taskMapper.updateByPrimaryKeySelective(record);
        }
    
        @Override
        public int deleteByPrimaryKey(Integer id) {
            return taskMapper.deleteByPrimaryKey(id);
        }
    
        /**
         * 执行启动任务
         */
        private void doStartTask(ScheduledTaskVO scheduledTask) {
            try {
                //任务key
                String taskKey = scheduledTask.getTaskkey();
                //定时表达式
                String taskCron = scheduledTask.getTaskcron();
                //获取需要定时调度的接口
                ScheduledTaskJob scheduledTaskJob = scheduledTaskJobMap.get(taskKey);
                LOGGER.info(">>>>>> 任务 [ {} ] ,cron={"+ scheduledTask.getTaskdesc()+"}---bean名称:"+taskKey+"---表达式:"+taskCron);
                ScheduledFuture scheduledFuture = threadPoolTaskScheduler.schedule(scheduledTaskJob,
                        new Trigger() {
                            @Override
                            public Date nextExecutionTime(TriggerContext triggerContext) {
                                CronTrigger cronTrigger = new CronTrigger(taskCron);
                                return cronTrigger.nextExecutionTime(triggerContext);
                            }
                        });
                //将启动的任务放入 map
                scheduledFutureMap.put(taskKey, scheduledFuture);
            }catch (Exception e){
                LOGGER.info("启动定时任务报错:"+e.toString());
                e.printStackTrace();
            }
        }
    
        /**
         * 任务是否已经启动
         */
        private Boolean isStart(String taskKey) {
            //校验是否已经启动
            if (scheduledFutureMap.containsKey(taskKey)) {
                if (!scheduledFutureMap.get(taskKey).isCancelled()) {
                    return true;
                }
            }
            return false;
        }
    }
    
    

    BeanContext

    package com.xnhy.educationadmin.util;
    
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    //手动获取Spring中的bean  注意这个类要一定交给spring来管理
    @Component
    public class BeanContext implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext;
    
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            BeanContext.applicationContext = applicationContext;
        }
    
        public static ApplicationContext getApplicationContext(){
            return applicationContext;
        }
    
        @SuppressWarnings("unchecked")
        public static <T> T getBean(String name) throws BeansException {
            return (T)applicationContext.getBean(name);
        }
    
        public static <T> T getBean(Class<T> clz) throws BeansException {
            return (T)applicationContext.getBean(clz);
        }
    }
    
    

    初始化加载数据

    package com.xnhy.educationadmin.controller.schedule;
    
    import com.xnhy.educationadmin.dao.common.ScheduledTaskMapper;
    import com.xnhy.educationadmin.domain.common.ScheduledTaskVO;
    import com.xnhy.educationadmin.service.schedule.ScheduledTaskService;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @see @Order注解的执行优先级是按value值从小到大顺序。
     * 项目启动完毕后开启需要自启的任务
     */
    @Component
    @Order(value = 1)
    public class ScheduledTaskRunner implements ApplicationRunner {
        /**
         * 日志
         */
        private static final Logger LOGGER = LogManager.getLogger(ScheduledTaskRunner.class);
    
        @Autowired
        private ScheduledTaskMapper taskMapper;
    
        @Autowired
        private ScheduledTaskService scheduledTaskService;
    
        /**
         * 程序启动完毕后,需要自启的任务
         */
        @Override
        public void run(ApplicationArguments applicationArguments) throws Exception {
            LOGGER.info(" >>>>>> 项目启动完毕, 开启 => 需要自启的任务 开始!");
            List<ScheduledTaskVO> scheduledTaskBeanList = taskMapper.getAllNeedStartTask();
            scheduledTaskService.initAllTask(scheduledTaskBeanList);
            LOGGER.info(" >>>>>> 项目启动完毕, 开启 => 需要自启的任务 结束!");
        }
    }
    

    定时任务加载service需要BeanContext,不然会报错空指针异常

    ......其他定时任务
      private OperationService operationService ;
    
        @Override
        public void run() {
            try {
                operationService = BeanContext.getApplicationContext().getBean(OperationService.class);
                log.info("------------运营位定时任务---start");
                ......
    

    部分sql,添加修改的省略了

    
      <sql id="queryConditions">
        <!-- 查询条件 -->
        <if test='taskdesc != null  and taskdesc !=""'>
          and x.taskdesc LIKE concat('%',#{taskdesc,jdbcType=VARCHAR},'%')
        </if>
      </sql>
      <!--  总数-->
      <select id="countScheduledTask" resultType="java.lang.Long" parameterType="com.xnhy.educationadmin.domain.common.ScheduledTaskVO">
        select
        count(x.id)
        from bj_xnhy_scheduled_task x
        where 1 = 1
        <include refid="queryConditions"/>
      </select>
    
      <!-- 列表 -->
      <select id="listScheduledTask" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List" />
        from bj_xnhy_scheduled_task x
        where 1 = 1
        <include refid="queryConditions"/>
        ORDER BY x.createtime DESC
        <if test='page != null and limit != null'>
          limit #{page,jdbcType=INTEGER},#{limit,jdbcType=INTEGER}
        </if>
      </select>
    
      <!-- 根据key 获取 任务信息-->
      <select id="getByKey" resultType="com.xnhy.educationadmin.domain.common.ScheduledTaskVO"
        parameterType="java.lang.String">
          SELECT x.*
          FROM bj_xnhy_scheduled_task x
          WHERE x.taskkey = #{taskKey,jdbcType=VARCHAR}
      </select>
    
      <!--获取程序初始化需要自启的任务信息-->
      <select id="getAllNeedStartTask" resultType="com.xnhy.educationadmin.domain.common.ScheduledTaskVO">
        SELECT x.*
        FROM bj_xnhy_scheduled_task X
        WHERE x.del =1 AND x.initstartflag = 1
      </select>
    
      <!-- 获取所有任务-->
      <select id="getAllTask" resultType="com.xnhy.educationadmin.domain.common.ScheduledTaskVO">
         SELECT x.*
         FROM bj_xnhy_scheduled_task x WHERE x.del =1
      </select>
    

    ScheduledTaskVO

    package com.xnhy.educationadmin.domain.common;
    
    import com.xnhy.educationadmin.domain.system.BasicDO;
    import lombok.Data;
    
    /**
     *
     * This class was generated by MyBatis Generator.
     * This class corresponds to the database table bj_xnhy_scheduled_task
     *
     * @mbg.generated do_not_delete_during_merge
     */
    @Data
    public class ScheduledTaskVO extends BasicDO {
        /**
         * Database Column Remarks:
         *   主键
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.id
         *
         * @mbg.generated
         */
        private Integer id;
    
        /**
         * Database Column Remarks:
         *   任务key值(使用bean名称)
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.taskkey
         *
         * @mbg.generated
         */
        private String taskkey;
    
        /**
         * Database Column Remarks:
         *   任务描述
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.taskdesc
         *
         * @mbg.generated
         */
        private String taskdesc;
    
        /**
         * Database Column Remarks:
         *   任务表达式
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.taskcron
         *
         * @mbg.generated
         */
        private String taskcron;
    
        /**
         * Database Column Remarks:
         *   程序初始化是否启动 1 是 0 否
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.initstartflag
         *
         * @mbg.generated
         */
        private Integer initstartflag;
    
        /**
         * 当前是否已启动
         */
        private boolean startFlag;
        /**
         * Database Column Remarks:
         *   创建时间
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.createtime
         *
         * @mbg.generated
         */
        private String createtime;
    
        /**
         * Database Column Remarks:
         *   创建工作人员
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.createuser
         *
         * @mbg.generated
         */
        private String createuser;
    
        /**
         * Database Column Remarks:
         *   创建人员id
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.createuserid
         *
         * @mbg.generated
         */
        private Integer createuserid;
    
        /**
         * Database Column Remarks:
         *   是否删除
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.del
         *
         * @mbg.generated
         */
        private Integer del;
    
        /**
         * Database Column Remarks:
         *   修改人员
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.updateuser
         *
         * @mbg.generated
         */
        private String updateuser;
    
        /**
         * Database Column Remarks:
         *   修改人员id
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.updateuserid
         *
         * @mbg.generated
         */
        private Integer updateuserid;
    
        /**
         * Database Column Remarks:
         *   修改时间
         *
         * This field was generated by MyBatis Generator.
         * This field corresponds to the database column bj_xnhy_scheduled_task.updatetime
         *
         * @mbg.generated
         */
        private String updatetime;
    }
    
    更多相关内容
  • spring-cloud-alibaba+dubbo+nacos+quartz以yml配置方式实现
  • springboot整合quartz,实现: 1.引入maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </...

    quartz简介:查看Quartz简介
    获取本文完整demo请访问:git地址
    springboot整合quartz,实现:

    1.引入maven依赖

    <dependency>
    	<groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>
    

    2.配置文件加入以下配置(在mysql,mybatis-plus等配置好的情况下,若没配置好,请下载完整demo):

    #quartz
    #自启动,false则不执行定时任务
    spring.quartz.auto-startup=true
    spring.quartz.job-store-type=jdbc
    spring.quartz.properties.org.quartz.scheduler.instanceName=clusteredScheduler
    spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
    spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
    #持久化到数据库
    spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    # 打开集群配置
    spring.quartz.properties.org.quartz.jobStore.isClustered=true
    # 设置集群检查间隔100s
    spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=10000
    spring.quartz.properties.org.quartz.jobStore.useProperties=false
    spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
    spring.quartz.properties.org.quartz.threadPool.threadCount=15
    spring.quartz.properties.org.quartz.threadPool.threadPriority=5
    spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
    

    3.数据库建表,语句如下

    DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;  
    DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;  
    DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;  
    DROP TABLE IF EXISTS QRTZ_LOCKS;  
    DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;  
    DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;  
    DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;  
    DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;  
    DROP TABLE IF EXISTS QRTZ_TRIGGERS;  
    DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;  
    DROP TABLE IF EXISTS QRTZ_CALENDARS;  
      
    CREATE TABLE QRTZ_JOB_DETAILS(  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    JOB_NAME VARCHAR(200) NOT NULL,  
    JOB_GROUP VARCHAR(200) NOT NULL,  
    DESCRIPTION VARCHAR(250) NULL,  
    JOB_CLASS_NAME VARCHAR(250) NOT NULL,  
    IS_DURABLE VARCHAR(1) NOT NULL,  
    IS_NONCONCURRENT VARCHAR(1) NOT NULL,  
    IS_UPDATE_DATA VARCHAR(1) NOT NULL,  
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,  
    JOB_DATA BLOB NULL,  
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    JOB_NAME VARCHAR(200) NOT NULL,  
    JOB_GROUP VARCHAR(200) NOT NULL,  
    DESCRIPTION VARCHAR(250) NULL,  
    NEXT_FIRE_TIME BIGINT(13) NULL,  
    PREV_FIRE_TIME BIGINT(13) NULL,  
    PRIORITY INTEGER NULL,  
    TRIGGER_STATE VARCHAR(16) NOT NULL,  
    TRIGGER_TYPE VARCHAR(8) NOT NULL,  
    START_TIME BIGINT(13) NOT NULL,  
    END_TIME BIGINT(13) NULL,  
    CALENDAR_NAME VARCHAR(200) NULL,  
    MISFIRE_INSTR SMALLINT(2) NULL,  
    JOB_DATA BLOB NULL,  
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)  
    REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_SIMPLE_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    REPEAT_COUNT BIGINT(7) NOT NULL,  
    REPEAT_INTERVAL BIGINT(12) NOT NULL,  
    TIMES_TRIGGERED BIGINT(10) NOT NULL,  
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_CRON_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    CRON_EXPRESSION VARCHAR(120) NOT NULL,  
    TIME_ZONE_ID VARCHAR(80),  
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_SIMPROP_TRIGGERS  
      (            
        SCHED_NAME VARCHAR(120) NOT NULL,  
        TRIGGER_NAME VARCHAR(200) NOT NULL,  
        TRIGGER_GROUP VARCHAR(200) NOT NULL,  
        STR_PROP_1 VARCHAR(512) NULL,  
        STR_PROP_2 VARCHAR(512) NULL,  
        STR_PROP_3 VARCHAR(512) NULL,  
        INT_PROP_1 INT NULL,  
        INT_PROP_2 INT NULL,  
        LONG_PROP_1 BIGINT NULL,  
        LONG_PROP_2 BIGINT NULL,  
        DEC_PROP_1 NUMERIC(13,4) NULL,  
        DEC_PROP_2 NUMERIC(13,4) NULL,  
        BOOL_PROP_1 VARCHAR(1) NULL,  
        BOOL_PROP_2 VARCHAR(1) NULL,  
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)   
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_BLOB_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    BLOB_DATA BLOB NULL,  
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
    INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),  
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_CALENDARS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    CALENDAR_NAME VARCHAR(200) NOT NULL,  
    CALENDAR BLOB NOT NULL,  
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_FIRED_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    ENTRY_ID VARCHAR(95) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    INSTANCE_NAME VARCHAR(200) NOT NULL,  
    FIRED_TIME BIGINT(13) NOT NULL,  
    SCHED_TIME BIGINT(13) NOT NULL,  
    PRIORITY INTEGER NOT NULL,  
    STATE VARCHAR(16) NOT NULL,  
    JOB_NAME VARCHAR(200) NULL,  
    JOB_GROUP VARCHAR(200) NULL,  
    IS_NONCONCURRENT VARCHAR(1) NULL,  
    REQUESTS_RECOVERY VARCHAR(1) NULL,  
    PRIMARY KEY (SCHED_NAME,ENTRY_ID))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_SCHEDULER_STATE (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    INSTANCE_NAME VARCHAR(200) NOT NULL,  
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,  
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,  
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_LOCKS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    LOCK_NAME VARCHAR(40) NOT NULL,  
    PRIMARY KEY (SCHED_NAME,LOCK_NAME))  
    ENGINE=InnoDB;  
      
    CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);  
    CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);  
      
    CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);  
    CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);  
    CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);  
    CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);  
    CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);  
    CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);  
    CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);  
    CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);  
    CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);  
    CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);  
    CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);  
    CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);  
      
    CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);  
    CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);  
    CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);  
    CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);  
    CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);  
    CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);  
      
    
    

    4.编写定时任务:注意需要实现Job接口并实现execute方法即可,需要定时任务相关数据可从JobExecutionContext中取,编写一个简单的定时打印指定字符串:

    public class PrintWordTask implements Job {
    
    
        @Override
        public void execute(JobExecutionContext jobExecutionContext) {
            JobDetail jobDetail = jobExecutionContext.getJobDetail();
            JobKey key = jobDetail.getKey();
            String name = key.getName();
            String group = key.getGroup();
            String jobKey = name + group;
            String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
            System.out.println(jobKey+"PrintWordsJob start at:" + printTime + ", prints: Hello Job-" + new Random().nextInt(100));
        }
    }
    

    5.实现定时任务列表,新增,删除,修改,中断,恢复,立即执行等功能

    public interface QrtzJobDetailsService extends IService<QrtzJobDetails> {
        List<QrtzTriggers> listQuartzEntity(QrtzJobDetails quartz, Integer pageNo, Integer pageSize) ;
        
        boolean save(QrtzJobDetails quartz) ;
    
        boolean deleteJob(QrtzJobDetails quartz);
    
        boolean pauseJob(QrtzJobDetails quartz);
    
        void resumeJob(QrtzJobDetails qrtzJobDetails);
    
        void updateJob(QrtzJobDetails qrtzJobDetails);
    
        void triggerJob(QrtzJobDetails qrtzJobDetails);
    
    @Slf4j
    @Service
    public class QrtzJobDetailsServiceImpl extends ServiceImpl<QrtzJobDetailsMapper, QrtzJobDetails> implements QrtzJobDetailsService {
    
        @Autowired
        private Scheduler scheduler ;
        @Resource
        private QrtzJobDetailsMapper qrtzJobDetailsMapper;
    
        @Override
        public List<QrtzTriggers> listQuartzEntity(QrtzJobDetails quartz, Integer pageNo, Integer pageSize) {
            return qrtzJobDetailsMapper.listQuartzEntity(quartz);
        }
    
        /**
         * 保存定时任务
         * @param quartz
         * @return
         */
        @Override
        @Transactional
        public boolean save(QrtzJobDetails quartz) {
            Assert.notNull(quartz.getCronExpression(), "cron表达式不能为空");
            Assert.notNull(quartz.getJobClassName(),"定时任务代码位置不能为空");
            //jobName+jobGroup不能重复,可以理解为jobName+jobGroup作为任务的唯一标识
            String uuid = "testQuartz"+ UUID.randomUUID().toString();
                quartz.setJobName(uuid);
                quartz.setJobGroup(uuid);
            try {
                //如果是修改  展示旧的 任务
                if (quartz.getOldJobGroup() != null) {
                    JobKey key = new JobKey(quartz.getOldJobName(), quartz.getOldJobGroup());
                    scheduler.deleteJob(key);
                }
                HashMap<String, Integer> map = new HashMap<>();
                map.put("id", 123);
                //通过这个可往定时任务传参,用处不大
                JobDataMap jobDataMap = new JobDataMap(map);
                Class cls = Class.forName(quartz.getJobClassName());
                cls.newInstance();
                //构建job信息
                JobDetail job = JobBuilder.newJob(cls)
                        .withIdentity(quartz.getJobName(), quartz.getJobGroup())
                        .withDescription(quartz.getDescription())
                        .usingJobData(jobDataMap)
                        .build();
                // 触发时间点
                CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression());
                Trigger trigger = TriggerBuilder.newTrigger()
                        .withIdentity("trigger" + quartz.getJobName(), quartz.getJobGroup())
                        .withDescription(quartz.getDescription())
                        .startNow().withSchedule(cronScheduleBuilder).build();
                //交由Scheduler安排触发
                scheduler.scheduleJob(job, trigger);
                scheduler.start();
            } catch (Exception e) {
                log.error("定时任务新增失败:", e);
            }
            return true;
        }
    
        /**
         * 删除定时任务
         * @param quartz
         * @return
         */
        @Override
        @Transactional
        public boolean deleteJob(QrtzJobDetails quartz) {
            Assert.notNull(quartz.getJobName(), "jobName不能为空");
            Assert.notNull(quartz.getJobGroup(),"jobGroup不能为空");
            boolean res = true;
            try {
                String jobName = quartz.getJobName();
                String jobGroup = quartz.getJobGroup();
                JobKey jobKey = new JobKey(jobName, jobGroup);
                res = scheduler.deleteJob(jobKey);
            } catch (Exception e) {
                log.error("删除定时任务失败:", e);
            }
            return res;
        }
    
        /**
         * 暂停定时任务
         * @param quartz
         * @return
         */
        @Override
        public boolean pauseJob(QrtzJobDetails quartz) {
            Assert.notNull(quartz.getJobName(), "jobName不能为空");
            Assert.notNull(quartz.getJobGroup(),"jobGroup不能为空");
            boolean res = true;
            try {
                JobKey jobKey = new JobKey(quartz.getJobName(), quartz.getJobGroup());
                scheduler.pauseJob(jobKey);
            } catch (Exception e) {
                log.error("终止定时任务异常:", e);
            }
            return res;
        }
    
        /**
         * 恢复定时任务
         * @param quartz
         */
        @Override
        public void resumeJob(QrtzJobDetails quartz) {
            Assert.notNull(quartz.getJobName(), "jobName不能为空");
            Assert.notNull(quartz.getJobGroup(),"jobGroup不能为空");
            try {
                JobKey jobKey = new JobKey(quartz.getJobName(), quartz.getJobGroup());
                scheduler.resumeJob(jobKey);
            } catch (Exception e) {
                log.error("恢复定时任务异常:", e);
            }
        }
    
    
        /**
         * 更新定时任务;这里只更新description,jobClassName,cronExpression三个字段
         * @param quartz
         */
        @Override
        @Transactional
        public void updateJob(QrtzJobDetails quartz) {
            Assert.notNull(quartz.getJobName(), "jobName不能为空");
            Assert.notNull(quartz.getJobGroup(),"jobGroup不能为空");
            try {
                String jobName = quartz.getJobName();
                String jobGroup = quartz.getJobGroup();
                Assert.notNull(jobName, "jobName不能为空");
                Assert.notNull(jobGroup, "jobGroup不能为空");
                Assert.notNull(quartz.getCronExpression(), "cron表达式不能为空");
                QrtzTriggers qrtzTriggers = qrtzJobDetailsMapper.getTriggerByJobKey( jobName, jobGroup);
                Assert.notNull(qrtzTriggers, "trigger不存在,定时任务异常");
                String triggerName = qrtzTriggers.getTriggerName();
                String triggerGroup = qrtzTriggers.getTriggerGroup();
                TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroup);
                CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression());
                CronTrigger trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerGroup).withSchedule(cronScheduleBuilder).withDescription(quartz.getDescription()).build();
                scheduler.rescheduleJob(triggerKey, trigger);
                QrtzJobDetails newQrtzJobDetails = new QrtzJobDetails();
                newQrtzJobDetails.setId(quartz.getId());
                newQrtzJobDetails.setDescription(quartz.getDescription());
                newQrtzJobDetails.setJobClassName(quartz.getJobClassName());
                QueryWrapper<QrtzJobDetails> wrapper = new QueryWrapper<>();
                wrapper.lambda().eq(QrtzJobDetails::getId, quartz.getId());
                super.update(newQrtzJobDetails, wrapper);
            } catch (Exception e) {
                log.error("修改定时任务异常:", e);
            }
    
        }
    
        @Override
        public void triggerJob(QrtzJobDetails quartz) {
            Assert.notNull(quartz.getJobName(), "jobName不能为空");
            Assert.notNull(quartz.getJobGroup(),"jobGroup不能为空");
            try{
                JobKey jobKey = new JobKey(quartz.getJobName(), quartz.getJobGroup());
                scheduler.triggerJob(jobKey);
            }catch (Exception e){
                log.error("触发定时任务失败:",e);
            }
        }
    
    }
    
    

    新增(每5妙执行一次打印任务):postMan截图
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • SpringBoot整合Quartz定时任务框架,动态修改cron表达式执行任务

    说到定时任务,估计都用过。

    ①、比如每天15点给lilei发邮件通知等,这种可以直接使用注解@Scheduled标注在一个方法上

    ②、但是如果我想每天14点发邮件,那是不是得改代码再重启服务,于是我们想到表达式写到配置文件中,再重启服务,相对于前面的可能简单一点

    ③、那我们还有没更简单的,达到动态修改执行时间且不需要重启服务,答案是有的。也就是本文所要说的。

    本文只是简单写了个demo,具体业务自行修改添加

    首先pom.xml引入Quartz

     <!-- 定时任务 -->
            <dependency>
                <groupId>org.quartz-scheduler</groupId>
                <artifactId>quartz</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>com.mchange</groupId>
                        <artifactId>c3p0</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

    创建数据库:

    CREATE TABLE `sys_job` (
      `id` varchar(64) NOT NULL COMMENT '任务ID',
      `job_name` varchar(64) NOT NULL DEFAULT '' COMMENT '任务名称',
      `job_group` varchar(64) NOT NULL DEFAULT 'DEFAULT' COMMENT '任务组名',
      `invoke_target` varchar(500) DEFAULT NULL COMMENT '调用目标字符串',
      `cron_expression` varchar(255) DEFAULT '' COMMENT 'cron执行表达式',
      `misfire_policy` varchar(20) DEFAULT '1' COMMENT '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
      `concurrent` char(1) DEFAULT '0' COMMENT '是否并发执行(0允许 1禁止)',
      `status` char(1) DEFAULT '1' COMMENT '状态(0正常 1暂停)',
      `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
      `create_time` datetime DEFAULT NULL COMMENT '创建时间',
      `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
      `update_time` datetime DEFAULT NULL COMMENT '更新时间',
      `remark` varchar(500) DEFAULT '' COMMENT '备注信息',
      `full_fixed` int(2) DEFAULT NULL COMMENT '全局设置',
      `cron_description` varchar(255) DEFAULT NULL COMMENT 'cron表达式描述',
      `parameter` varchar(255) DEFAULT NULL COMMENT '参数,功能项',
      PRIMARY KEY (`id`,`job_name`,`job_group`) USING BTREE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='定时任务调度表';

    对应实体类:

    @Data
    @EqualsAndHashCode(callSuper = true)
    @Accessors(chain = true)
    @ApiModel(value="SysJob对象", description="定时任务调度表")
    public class SysJob extends BaseEntity {
    
        private static final long serialVersionUID=1L;
    
        @ApiModelProperty(value = "任务名称")
        private String jobName;
    
        @ApiModelProperty(value = "任务组名")
        private String jobGroup;
    
        @ApiModelProperty(value = "调用目标字符串")
        private String invokeTarget;
    
        @ApiModelProperty(value = "cron执行表达式")
        private String cronExpression;
    
        @ApiModelProperty(value = "定时描述")
        private String cronDescription;
    
        @ApiModelProperty(value = "计划执行错误策略(1立即执行 2执行一次 3放弃执行)")
        private String misfirePolicy;
    
        @ApiModelProperty(value = "是否并发执行(0允许 1禁止)")
        private String concurrent;
    
        @ApiModelProperty(value = "状态(0正常 1暂停)")
        private String status;
    
        @ApiModelProperty(value = "创建者")
        private String createBy;
    
        @ApiModelProperty(value = "创建时间")
        @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
        @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
        private LocalDateTime createTime;
    
        @ApiModelProperty(value = "更新者")
        private String updateBy;
    
        @ApiModelProperty(value = "更新时间")
        @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
        @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
        private LocalDateTime updateTime;
    
        @ApiModelProperty(value = "备注信息")
        private String remark;
    
    
        @ApiModelProperty(value = "参数功能项,即对应的指令 比如:'00000000'")
        private String parameter;
    
    
        //@ApiModelProperty(value = "下次执行时间")
        //private LocalDateTime nextExecutionTime;
    
        @ApiModelProperty(value = "全局定时 0-否| 1-是")
        private Integer fullFixed;
    }

    任务工具类

    public class ScheduleUtil {
    
    
        /**
         * 获取任务执行类
         *
         * @param sysJob
         * @return
         * @throws Exception
         */
        private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) throws Exception {
            String className = sysJob.getInvokeTarget();
    //        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
    //        return isConcurrent ? SampleJob.class : QuartzDisallowConcurrentExecution.class;
            Class<Job> jobClass = null;
            try {
                if (!isValidClassName(className)) {
                    jobClass = (Class<Job>) SpringUtils.getBean(className);
                } else {
                    jobClass = (Class<Job>) Class.forName(className);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new Exception("任务类不存在");
            }
    
    
            return jobClass;
        }
    
        /**
         * 构建任务触发对象
         */
        public static TriggerKey getTriggerKey(String jobId, String jobGroup) {
            return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
        }
    
        /**
         * 构建任务键对象
         */
        public static JobKey getJobKey(String jobId, String jobGroup) {
            return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
        }
    
        /**
         * 创建定时任务
         */
        public static void createScheduleJob(Scheduler scheduler, SysJob job) throws Exception {
            Class<? extends Job> jobClass = getQuartzJobClass(job);
            // 构建job信息
            String jobId = job.getId();
            String jobGroup = job.getJobGroup();
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
    
            // 表达式调度构建器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
    
            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup)).withSchedule(cronScheduleBuilder).build();
    
            // 放入参数,运行时的方法可以获取
            jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
    
            // 判断是否存在
            if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
                // 防止创建时存在数据问题 先移除,然后在执行创建操作
                scheduler.deleteJob(getJobKey(jobId, jobGroup));
            }
    
            scheduler.scheduleJob(jobDetail, trigger);
    
    //        // 暂停任务
    //        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
    //            scheduler.pauseJob(getJobKey(jobId, jobGroup));
    //        }
        }
    
        /**
         * 设置定时任务策略
         */
        public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb) throws Exception {
            switch (job.getMisfirePolicy()) {
                case ScheduleConstants.MISFIRE_DEFAULT:
                    return cb;
                case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
                    return cb.withMisfireHandlingInstructionIgnoreMisfires();
                case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
                    return cb.withMisfireHandlingInstructionFireAndProceed();
                case ScheduleConstants.MISFIRE_DO_NOTHING:
                    return cb.withMisfireHandlingInstructionDoNothing();
                default:
                    throw new RuntimeException("The task misfire policy '" + job.getMisfirePolicy()
                            + "' cannot be used in cron schedule tasks");
            }
        }
    
        public static boolean isValidClassName(String invokeTarget) {
            return StringUtils.countMatches(invokeTarget, ".") > 1;
        }
    
    }
    }
    @Service
    public class SysJobServiceImpl extends ServiceImpl<SysJobMapper, SysJob> implements ISysJobService {
    
        @Autowired
        private Scheduler scheduler;
    
    
        /**
         * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
         */
        @PostConstruct
        public void init() throws Exception {
            scheduler.clear();
            List<SysJob> jobList = baseMapper.selectList(new QueryWrapper<>());
            for (SysJob job : jobList) {
                ScheduleUtil.createScheduleJob(scheduler, job);
            }
        }
    
        /**
         * 保存
         *
         * @param sysJob
         * @return
         * @throws Exception
         */
        @Override
        public boolean insert(SysJob sysJob) throws Exception {
            boolean save = save(sysJob);
            if (save) {
                ScheduleUtil.createScheduleJob(scheduler, sysJob);
            }
            return save;
        }
    
        @Override
        public boolean deleteJob(SysJob job) throws Exception {
            String jobId = job.getId();
            String jobGroup = job.getJobGroup();
            boolean del = removeById(jobId);
            if (del) {
                scheduler.deleteJob(ScheduleUtil.getJobKey(jobId, jobGroup));
            }
            return del;
        }
    
        @Override
        public boolean deleteJob(String primary) throws Exception {
            SysJob sysJob = this.getBaseMapper().selectOne(new QueryWrapper<>());
            return deleteJob(sysJob);
        }
    
        @Override
        public void deleteByPrimarys(String[] jobIds) throws Exception {
            for (String jobId : jobIds) {
                SysJob job = baseMapper.selectById(jobId);
                deleteJob(job);
            }
        }
    
        @Override
        public boolean updateByPrimary(SysJob sysJob) throws Exception {
    
            SysJob properties = baseMapper.selectById(sysJob.getId());
            boolean update = update(sysJob, new QueryWrapper<>());
            if (update) {
                updateSchedulerJob(sysJob, properties.getJobGroup());
            }
            return update;
        }
    
        /**
         * @param page
         * @param queryWrapper
         * @描述:分页
         */
        @Override
        public IPage<SysJob> page(IPage<SysJob> page, QueryWrapper<SysJob> queryWrapper) throws Exception {
            return baseMapper.selectPage(page, queryWrapper);
        }
    
        /**
         * @param queryWrapper
         * @描述:条件查询
         */
        @Override
        public List<SysJob> select(Wrapper<SysJob> queryWrapper) throws Exception {
            return baseMapper.selectList(queryWrapper);
        }
    
    
    
    
        /**
         * 更新任务
         *
         * @param job      任务对象
         * @param jobGroup 任务组名
         */
        public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, Exception {
            String jobId = job.getId();
            // 判断是否存在
            JobKey jobKey = ScheduleUtil.getJobKey(jobId, jobGroup);
            if (scheduler.checkExists(jobKey)) {
                // 防止创建时存在数据问题 先移除,然后在执行创建操作
                scheduler.deleteJob(jobKey);
            }
            ScheduleUtil.createScheduleJob(scheduler, job);
        }
    
    }
    
    @Component("sampleJob")
    public class SampleJob extends AbstractQuartzJob {
    
    
        //Job的实例是在真正调度JobDetail中的Job实现类时进行实例化的,此对象由框架本身进行管理,所以实例化的对象并没有交给Spring来管理
    
    
        // 需要注入的依赖bean
        private static ITaskService taskService;
    
    
        // 定义一个set方法
        @Autowired
        public void setTaskService(ITaskService taskService) {
            SampleJob.taskService = taskService;
        }
    
    
    //    private ITaskService taskService = SpringUtils.getBean( "taskService");
    
        @Override
        protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {
            System.out.println("start");
            System.out.println("sysJob = " + sysJob);
            System.out.println("end");
    //        String taskCode = context.getJobDetail().getKey().getName();
    //        //具体任务执行的业务
    //        taskService.command(sysJob);
        }
    }

    最终看下测试效果

     完美!

    展开全文
  • 本篇文章主要介绍了springboot整合Quartz实现动态配置定时任务的方法,非常具有实用价值,需要的朋友可以参考下
  • springboot整合quartz定时任务(任务持久化到数据库)

    springboot整合quartz定时任务( JDBC作业存储方式)

    一、介绍

    Quartz提供两种基本作业存储类型:RAMJobStore、JDBC作业存储

    1. RAMJobStore
      RAM也就是内存,默认情况下Quartz会将任务调度存在内存中,这种方式性能是最好的,因为内存的速度是最快的。不好的地方就是数据缺乏持久性,但程序崩溃或者重新发布的时候,所有运行信息都会丢失。
      2、JDBC作业存储
      存到数据库之后,可以做单点也可以做集群,当任务多了之后,可以统一进行管理。关闭或者重启服务器,运行的信息都不会丢失。缺点就是运行速度快慢取决于连接数据库的快慢。

    本博客使用jdbc作业存储的方式,同时实现restFul请求对任务启停实现控制,当前应用springboot版本2.4.4。

    二、搭建工程

    • pom文件
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>quartz-job</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.4.4</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-batch</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.16</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-quartz</artifactId>
             </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.4</version>
            </dependency>
    
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper</artifactId>
                <version>4.1.0</version>
            </dependency>
            <!-- <dependency>
                 <groupId>org.springframework.session</groupId>
                 <artifactId>spring-session-data-redis</artifactId>
             </dependency>
     -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.batch</groupId>
                <artifactId>spring-batch-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-cache</artifactId>
            </dependency>
           <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
            <dependency>
                <groupId>org.xerial</groupId>
                <artifactId>sqlite-jdbc</artifactId>
                <version>3.32.3.2</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.7.13</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    • application.yml及application-dev.yml配置文件

    application.yml

    server:
      port: 8080
    spring:
      profiles:
        active: dev
    #数据库配置mysql数据库
    syx:
      database:
        url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
        driver: com.mysql.cj.jdbc.Driver
        userName: xxxx
        passwd: xxx
        validationQuery: select 1 from dual
        initSize: 3
        minIdle: 3
        maxActive: 10
        checkTable: false
        maxWaitTime: 60000
        evictionRunTime: 60000
        minEvictionIdleTime: 300000
        keepAlive: true
        testWhileIdle: true
        testOnBorrow: true
        testOnReturn: false
        poolPreparedStatement: true
        maxPoolPreparedStatementSizePerConnection: 20
        validateQueryTimeOut: 3
    

    application-dev.yml

    mybatis:
      mapper-locations: classpath:mapper/*Mapper.xml  #mapper文件的路径
    #showSql
    logging:
      level:
        com:
          syx:
            dao: debug
    
    • 数据库配置类,主要是为了绑定application.yml中的数据库配置
    package com.syx.microapplication.base;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    /**
     * @date: 2022-03-10 23:04
     * <p>数据源配置参数</p>
     */
    @Component
    @ConfigurationProperties(prefix = "syx.database")
    public class DataSourceConfigProperty {
    
        private String url;
    
        private String driver;
    
        private String userName;
    
        private String passwd;
    
        private String validationQuery = "select 1 from dual";
    
        //连接池初始大小
        private String initSize = "3";
    
        //最小连接数
        private String minIdle = "3";
    
        //最大连接数
        private String maxActive ="10";
    
        //是否开启表的初始化检查
        private boolean checkTable = false;
    
        //获取连接的最大等待时间单位为毫秒
        private long maxWaitTime;
    
        //空闲检测时间单位为毫秒
        private long evictionRunTime;
    
        //连接在池中最小生存时间单位毫秒
        private long minEvictionIdleTime;
    
        //
        private boolean keepAlive;
    
        private boolean testWhileIdle;
    
        //获取连接时是否检测连接有效
        private boolean testOnBorrow;
    
        //连接归还时是否检测连接有效
        private boolean testOnReturn;
    
        //是否缓存PrepareStatement
        private boolean poolPreparedStatement;
    
        //每个连接的  PrepareStatement缓存大小
        private int maxPoolPreparedStatementSizePerConnection;
    
        //连接检测超时设置
        private int validateQueryTimeOut;
    	//getters and setters....
    }
    
    • 应用配置
    package com.syx.microapplication.base;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    /**
     * @date: 2022-03-11 00:15
     * <p></p>
     */
    @Configuration
    @EnableAspectJAutoProxy
    @ComponentScan(AppConfig.COMPONENT_SCAN)
    @MapperScan(AppConfig.MAPPER_SCAN)
    public class AppConfig {
        //包扫描路径
        protected static final String COMPONENT_SCAN = "com.syx";
        //mybatis的dao路径
        protected static final String MAPPER_SCAN = "com.syx.**.dao";
    }
    
    • 数据源配置,本应用使用的是druid数据源
    package com.syx.microapplication.base;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.support.http.StatViewServlet;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.web.servlet.ServletRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @date: 2022-03-10 23:01
     * <p>数据源配置</p>
     */
    @Configuration
    @EnableTransactionManagement
    @ConditionalOnClass(DataSource.class)
    public class DataSourceConfig {
        @Autowired
        private DataSourceConfigProperty dataSourceConfigProperty;
        @Bean
        @Primary
        public DruidDataSource dataSource(){
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setUrl(dataSourceConfigProperty.getUrl());
            druidDataSource.setDriverClassName(dataSourceConfigProperty.getDriver());
            druidDataSource.setUsername(dataSourceConfigProperty.getUserName());
            druidDataSource.setPassword(dataSourceConfigProperty.getPasswd());
            druidDataSource.setInitialSize(Integer.parseInt(dataSourceConfigProperty.getInitSize()));
            druidDataSource.setMinIdle(Integer.parseInt(dataSourceConfigProperty.getMinIdle()));
            druidDataSource.setMaxActive(Integer.parseInt(dataSourceConfigProperty.getMaxActive()));
            druidDataSource.setMaxWait(dataSourceConfigProperty.getMaxWaitTime());
            druidDataSource.setTimeBetweenEvictionRunsMillis(dataSourceConfigProperty.getEvictionRunTime());
            druidDataSource.setMinEvictableIdleTimeMillis(dataSourceConfigProperty.getMinEvictionIdleTime());
            druidDataSource.setTestWhileIdle(dataSourceConfigProperty.isTestWhileIdle());
            druidDataSource.setTestOnBorrow(dataSourceConfigProperty.isTestOnBorrow());
            druidDataSource.setTestOnReturn(dataSourceConfigProperty.isTestOnReturn());
            druidDataSource.setValidationQuery(dataSourceConfigProperty.getValidationQuery());
            return druidDataSource;
        }
        /**
         * druid监控平台
         * @return
         */
        @Bean
        public ServletRegistrationBean<StatViewServlet> servletRegistrationBean(){
            ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>();
            StatViewServlet servlet = new StatViewServlet();
            registrationBean.setServlet(servlet);
            registrationBean.setName("druidView");
            registrationBean.setLoadOnStartup(2);
            List<String> urlMapping = new ArrayList<>();
            urlMapping.add("/druid/*");
            registrationBean.setUrlMappings(urlMapping);
            return registrationBean;
        }
    }
    
    • quartz核心配置类QuartzConfig,该类主要是往spring容器中注入SchedulerFactoryBean,该类是quartz调度器的核心类。同时加载quartz.properyies配置文件,及维护trigger应用的xml配置文件,定义在configJobs目录下
    package com.syx.microapplication.base;
    
    import org.quartz.*;
    import org.quartz.impl.matchers.GroupMatcher;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.autoconfigure.AutoConfigureAfter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.ImportResource;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.scheduling.quartz.SchedulerFactoryBean;
    
    import javax.sql.DataSource;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @date: 2022-03-10 22:28
     * <p>
     *  * </p>
     */
    @Configuration
    @AutoConfigureAfter(DataSource.class)
    @ImportResource(value = {
            "classpath*:configJobs/*ApplicationContext.xml"
    })
    @PropertySource(value = {
            "classpath:quartz.properties"
    })
    public class QuartzConfig {
        private static final Logger LOGGER = LoggerFactory.getLogger(QuartzConfig.class);
    
    
        @Bean
        public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource,QuartzTriggers quartzTriggers){
            SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(){
                @Override
                public void afterPropertiesSet() throws Exception {
                    super.afterPropertiesSet();
                    //项目启动时打印任务信息
                    triggerMsgPrint(super.getScheduler());
                }
            };
            //配置数据源
            schedulerFactoryBean.setDataSource(dataSource);
            //设置quartz.properties
            schedulerFactoryBean.setConfigLocation(new ClassPathResource("quartz.properties"));
           //设置任务自启动
            schedulerFactoryBean.setAutoStartup(true);
            //设置调度器名称
            schedulerFactoryBean.setSchedulerName("SYX_SCHEDULER");
            
            //triggers维护在configJobs/*ApplicationContext.xml的文件中
            schedulerFactoryBean.setTriggers(quartzTriggers.getTriggers());
            schedulerFactoryBean.setOverwriteExistingJobs(true);
            return schedulerFactoryBean;
        }
    
    
        /**
         * 打印trigger信息
         * @param scheduler
         */
        private void triggerMsgPrint(Scheduler scheduler) throws SchedulerException {
    
            List<String> groupNames = scheduler.getTriggerGroupNames();
    
            for (String groupName : groupNames) {
    
                Set<TriggerKey> triggerKeys = scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(groupName));
    
                for (TriggerKey triggerKey : triggerKeys) {
    
                    Trigger trigger = scheduler.getTrigger(triggerKey);
    
                    JobDetail jobDetail = scheduler.getJobDetail(trigger.getJobKey());
                    //在使用java配置job时需要指定key为JobName
                    LOGGER.info("任务名->{}",jobDetail.getJobDataMap().getString("JobName"));
                    LOGGER.info("任务描述->{}",jobDetail.getDescription());
                    //需要指定  默认指定为0
                    LOGGER.info("重复执行次数->{}",jobDetail.getJobDataMap().getString("RepeatTime"));
                    //需要指定 默认为10ms 维护在JobDataMap
                    LOGGER.info("重跑时间间隔->{}",jobDetail.getJobDataMap().getString("RepeatInterval"));
                    if(trigger instanceof CronTrigger){
                        CronTrigger temp = (CronTrigger) trigger;
                        LOGGER.info("cron表达式->{}",temp.getCronExpression());
                        LOGGER.info("开始执行时间->{}",temp.getStartTime());
                    }
                    if(trigger instanceof SimpleTrigger){
                        SimpleTrigger temp = (SimpleTrigger) trigger;
                        LOGGER.info("触发时间->{}",temp.getFinalFireTime());
                        LOGGER.info("开始执行时间->{}",temp.getStartTime());
                    }
                    LOGGER.info("下次执行时间->{}",trigger.getNextFireTime());
                }
            }
        }
    }
    
    • QuartzTriggers配置类与configJobs/*ApplicationContext.xml对应,用于维护triggers
    package com.syx.microapplication.base;
    import org.quartz.Trigger;
    import java.util.List;
    /**
     * @date: 2022-03-11 20:49
     * <p>维护triggers</p>
     */
    public class QuartzTriggers {
        private List<Trigger> triggers;
        public Trigger[] getTriggers(){
            Trigger[] arr = new Trigger[this.triggers.size()];
            for (int i = 0; i < this.triggers.size(); i++) {
                arr[i] = this.triggers.get(i);
            }
            return arr;
        }
        public void setTriggers(List<Trigger> triggers) {
            this.triggers = triggers;
        }
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns= "http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!--加载任务trigger-->
        <import resource="classpath*:configJobs/jobs/*ApplicationContext.xml"/>
        <!--将加载的任务trigger维护到QuartzTriggers的list中-->
        <bean id="triggerCollection" class="com.syx.microapplication.base.QuartzTriggers">
            <property name="triggers">
                <list>
                    <ref bean="TestJobTrigger"/>
                </list>
            </property>
        </bean>
    </beans>
    
    • 启动类,启动类中我们要排除springboot的quartz自动配置,进而使用我们自定义的SchedulerFactoryBean 的配置。查看QuartzAutoConfiguration源码亦可知,该类的主要作用为,往容器中注入了SchedulerFactoryBean。
    package com.syx.microapplication;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
    /**
     - @date: 2022-03-10 23:49
     - <p></p>
     */
    @SpringBootApplication(exclude = {QuartzAutoConfiguration.class})
    public class MainApp {
        public static void main(String[] args) {
            SpringApplication.run(MainApp.class,args);
        }
    }
    

    三、新建 job

    • 新建测试job该任务必须实现org.quartz.Job接口。
    package com.syx.demon.job;
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    /**
     * @date: 2022-03-11 21:53
     * <p></p>
     */
    public class TestJob implements Job {
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            System.out.println("Hello world...");
        }
    }
    
    • 新建job对应的xml(这一步非常关键)
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--自定义job任务-->
        <bean id="TestJob" class="com.syx.demon.job.TestJob"/>
        <!--job任务纳管到JobDetailFactoryBean类中-->
        <bean id="TestJobName" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <property name="description" value="TestJob测试"/>
            <property name="group" value="TestJobGroup"/>
            <property name="jobClass" value="com.syx.demon.job.TestJob"/>
            <property name="durability" value="true"/>
            <property name="jobDataAsMap">
                <map>
                    <entry key="JobName" value="TestJob"/>
                    <entry key="RepeatTime" value="0"/>
                    <entry key="RepeatInterval" value="10"/>
                </map>
            </property>
        </bean>
    <!--将JobDetailFactoryBean配置到CronTriggerFactoryBean中,并指定cron表达式-->
        <bean id="TestJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
            <property name="jobDetail" ref="TestJobName"/>
            <property name="cronExpression" value="*/30 * * * * ?"/>
            <!--错过是否补跑 0,1是 2 否-->
            <property name="misfireInstruction" value="2"/>
        </bean>
    </beans>
    

    四、启动工程

    控制台打印了任务信息,同时任务也执行并输出了hello world…
    在这里插入图片描述

    数据库中记录了任务名,任务组及任务的class信息。
    在这里插入图片描述

    五、quartz扩展,通过http请求控制任务启停。

    • 新建quartz任务调度控制service
    package com.syx.microapplication.system.service;
    
    import com.syx.microapplication.system.bean.QuartzJobDetail;
    import org.quartz.*;
    import org.quartz.impl.matchers.GroupMatcher;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @date: 2022-03-12 16:20
     * <p></p>
     */
    @Service
    public class QuartzSchedulerService {
        @Autowired
        private Scheduler scheduler;
        private static final Logger LOGGER = LoggerFactory.getLogger(QuartzSchedulerService.class);
    
        /**
         * 查询所有任务
         * @return
         * @throws SchedulerException
         */
        public List<QuartzJobDetail> getJobDetail() throws SchedulerException {
            List<QuartzJobDetail> result = new ArrayList<>();
    
            List<String> groupNames = scheduler.getJobGroupNames();
            for (String groupName : groupNames) {
    
                Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
    
                for (JobKey jobKey : jobKeys) {
    
                    JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                    QuartzJobDetail jobInfo = new QuartzJobDetail();
                    jobInfo.setSchedulerName(scheduler.getSchedulerName());
                    jobInfo.setSchedulerInstanceId(scheduler.getSchedulerInstanceId());
                    jobInfo.setJobName(jobKey.getName());
                    jobInfo.setDescription(jobDetail.getDescription());
                    jobInfo.setDurability(jobDetail.isDurable());
                    jobInfo.setRecover(jobDetail.requestsRecovery());
                    jobInfo.setGroup(jobKey.getGroup());
                    jobInfo.setJobClass(jobDetail.getJobClass().getName());
                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
    
                    if(triggers!=null && !triggers.isEmpty()){
    
                        for (Trigger trigger : triggers) {
                            jobInfo.setState(scheduler.getTriggerState(trigger.getKey()).name());
                            jobInfo.setTriggersNum(triggers.size());
                            jobInfo.setNextFireTime(trigger.getNextFireTime());
                        }
                    }else{
                        jobInfo.setState("NONE");
                    }
                    result.add(jobInfo);
                }
            }
    
            return result;
        }
    
    
        /**
         * 删除job
         * @param jobName
         * @param jobGroup
         * @throws SchedulerException
         */
        public void deleteJob(String jobName,String jobGroup) throws SchedulerException {
            scheduler.deleteJob(JobKey.jobKey(jobName,jobGroup));
        }
    
    
        /**
         * 重启job
         * @param jobName
         * @param jobGroup
         * @throws SchedulerException
         */
        public void resumeJob(String jobName,String jobGroup) throws SchedulerException {
            scheduler.resumeJob(JobKey.jobKey(jobName,jobGroup));
        }
    
    
        /**
         * 暂停job
         * @param jobName
         * @param jobGroup
         * @throws SchedulerException
         */
        public void pause(String jobName,String jobGroup) throws SchedulerException {
            scheduler.pauseJob(JobKey.jobKey(jobName,jobGroup));
        }
    
        /**
         * 立即执行
         * @param jobName
         * @param jobGroup
         * @throws SchedulerException
         */
        public void triggerNow(String jobName,String jobGroup) throws SchedulerException {
            scheduler.triggerJob(JobKey.jobKey(jobName,jobGroup));
        }
    }
    
    • 任务详情包装类
    package com.syx.microapplication.system.bean;
    
    import com.syx.utils.IDUtil;
    
    import java.util.Date;
    import java.util.Map;
    
    /**
     * @date: 2022-03-12 15:40
     * <p>quartzJob的描述信息</p>
     */
    public class QuartzJobDetail {
    
        private String description;
    
        private boolean durability;
    
        private String group;
    
        private String jobClass;
    
        private Map<String,Object> jobDataMap;
    
        private String jobName;
    
        private Date nextFireTime;
    
        private int triggersNum;
    
        private String quartzInstanceId;
    
        private String schedulerInstanceId;
    
        private String schedulerName;
    
        private boolean recover;
    
        private String state;
    
        private String uuid=IDUtil.generateId();
    
    	//getters and setters
    }
    
    • 任务调度controller
    package com.syx.microapplication.system.controller;
    
    import com.syx.microapplication.system.bean.QuartzJobDetail;
    import com.syx.microapplication.system.service.QuartzSchedulerService;
    import org.quartz.SchedulerException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import java.util.List;
    /**
     * @date: 2022-03-12 15:31
     * <p></p>
     */
    @RestController
    @RequestMapping("/quartzJob")
    public class QuartzJobController {
    
        @Autowired
        private QuartzSchedulerService quartzSchedulerService;
        private static final Logger LOGGER = LoggerFactory.getLogger(QuartzJobController.class);
    
        @GetMapping
        public List<QuartzJobDetail> getJobDetail() throws SchedulerException {
            return quartzSchedulerService.getJobDetail();
        }
    
        /**
         * 删除job
         * @param jobName
         * @param jobGroup
         * @throws SchedulerException
         */
        @DeleteMapping
        public void deleteJob(String jobName,String jobGroup) throws SchedulerException {
            quartzSchedulerService.deleteJob(jobName,jobGroup);
            LOGGER.info("删除任务{}成功",jobName);
        }
    
    
        /**
         * 重启job
         * @param jobName
         * @param jobGroup
         * @throws SchedulerException
         */
        @GetMapping(path = "{jobName}/{jobGroup}/resume")
        public void resumeJob(@PathVariable(value = "jobName") String jobName,
                              @PathVariable(value = "jobGroup") String jobGroup) throws SchedulerException {
            quartzSchedulerService.resumeJob(jobName,jobGroup);
            LOGGER.info("重启任务{}成功",jobName);
        }
    
    
        /**
         * 暂停job
         * @param jobName
         * @param jobGroup
         * @throws SchedulerException
         */
        @GetMapping(path = "{jobName}/{jobGroup}/pause")
        public void pause(@PathVariable(value = "jobName") String jobName,
                          @PathVariable(value = "jobGroup") String jobGroup) throws SchedulerException {
           quartzSchedulerService.pause(jobName,jobGroup);
           LOGGER.info("暂停任务{}成功",jobName);
        }
    
        /**
         * 立即执行
         * @param jobName
         * @param jobGroup
         * @throws SchedulerException
         */
        @GetMapping(path = "{jobName}/{jobGroup}/triggerNow")
        public void triggerNow(@PathVariable(value = "jobName") String jobName,
                               @PathVariable(value = "jobGroup") String jobGroup) throws SchedulerException {
            quartzSchedulerService.triggerNow(jobName,jobGroup);
            LOGGER.info("任务{}启动成功",jobName);
        }
    }
    

    六、总结

    展开全文
  • SpringBoot整合Quartz定时任务 1、创建工程 2、创建任务类 package com.quartzjob.job.sysJob; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; ...
  • Springboot整合Quartz实现定时任务数据库动态配置,新增任务、修改cron表达式、暂停任务、恢复任务、删除任务等操作
  • springboot整合quartz,实现数据库方式执行定时任务。把定时任务信息存进数据库,项目启动后自动执行定时任务
  • SpringBoot整合Quartz 定时任务框架 1.Quartz介绍以及Quartz的使用思路 参考文档:https://blog.csdn.net/noaman_wgs/article/details/80984873 1.1.Quartz的介绍 ​ Quartz是OpenSymphony开源组织在Job scheduling...
  • springboot整合Quartz实现动态配置定时任务源码
  • SpringBoot整合Quartz实现动态定时任务,在页面动态展示,添加,暂停,删除定时任务. 并整合了MyBatis-plus, 感兴趣的小伙伴 可以试试
  • 在选择技术栈之前,一定要先明确一件...写这个主要是因为一直想写一下定时任务这个主题,这个算是写那篇文前期的铺垫和基础吧~本文没有聊到Java其他的实现定时任务的方法啥的~,只是对使用 Quartz 做了一个小实践。...
  • 背景 最近在做项目,项目中有个需求:需要使用定时任务,这个定时任务需要即时生效。 查看Quartz官网之后发现:Quartz提供两种基...
  • springboot 2.4.3 quartz 2.3.2 mysql 1. gradle导入依赖 implementation 'org.springframework.boot:spring-boot-starter-web' compile group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '...
  • 目前项目中需要写一个定时任务, 要求每天0点执行一段程序, 对于此需求最简便的方法当然是使用quartz了 1. 首先在pom.xml文件中加入quartz依赖 <!-- Quartz依赖 --> <dependency> <groupId>org....
  • } } } } /** * 获取一个Trigger的实例,不同的定时任务,分组可以相同,实例名必须不同 * @date: 2020年12月22日 * @param scheduleBuilder * @param name TriggerBuilder设置定时任务时要求每个定时任务的name不同 ...
  • Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成...
  • 目录 一 java原生实现定时任务SpringBoot整合quartz实现定时任务 1 导坐标 2 bean继承QuartzJobBean 3 配置类 定时任务应用场景:年度报表、秒杀商品上架、缓存统计报告 一 java原生实现定时任务 package ...
  • spring支持多种定时任务的实现。我们来介绍下使用spring的定时器和使用quartz定时器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
  • SpringBoot 整合定时任务 QuartzSpringBoot 内置定时任务 Task 代码详解
  • 上一章是改造整合redis实现启动服务即将热点数据保存在全局以及redis中,方便其他接口使用,本章整合quartz框架,实现定时任务的优化,前面整合的定时任务是使用的spring的Scheduled注解方式实现的,本章整合quartz...
  • 1.简单的controller进行调用测试。 @RestController @RequestMapping(&amp;amp;amp;quot;/quartz&... private QuartzScheduler quartzScheduler; @RequestMapping(&amp;amp;amp;quot;/st

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,781
精华内容 1,512
热门标签
关键字:

springboot整合quartz定时任务

spring 订阅