springboot实现quartz管理

简介

看完上篇之后,你会发现spring自带的schedule确实方便,而且十分简洁。但是我们在平常开发中时常会有面临着需求的改变,比如这个方法本来是中午12点执行的,现在要变成下午1点去执行,然而项目已经上线了,修改源码中@Scheduled注解中的cron表达式显然是不科学的。那么面对这种情况quartz给我们提供了很好的管理功能。


springboot整合quartz

github:https://github.com/mzd123/springboot_quartz

版本: boot:1.5.9.RELEASE

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>HikariCP-java6</artifactId>
                    <groupId>com.zaxxer</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.31</version>
        </dependency>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.7-dmr</version>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>
        <!-- 通用mapper -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>1.1.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

创建表结构: 刚开始学这个的时候,我发现所有关于quartz动态管理的项目表都是一样,最开始我以为都是抄的。每一个有自己想法的,后来我发现,这个表结构是quartz自带的。sql脚本位于:org.quartz.impl.jdbcjobstore包中。
这里写图片描述
quartz表: 这里我用的是:mysql_innodb.sql
这里写图片描述

配置quartz.properties:

#这个东西随便取的,自己开心就好
org.quartz.scheduler.instanceName=MyScheduler
#最多有5个任务同时在执行,如果有第六个任务将会被搁置
org.quartz.threadPool.threadCount=5
#如果用内存记录定时任务信息,应用重新启动后,定时任务信息将会丢失。
# 比如,用户A通过系统设置1小时后执行Z操作,设置好后的,因系统重新启动,新启动的系统将会丢失“1小时后执行Z操作”的定时任务。
#org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#如果,我们需要在系统意外(或非意外)重新启动后,仍保留定时任务信息,可以使用数据库存储定时任务信息。
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
#方言:org.quartz.impl.jdbcjobstore.StdJDBCDelegate---用于完全符合JDBC的驱动程序
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#表的前缀--- 默认就是QRTZ_
org.quartz.jobStore.tablePrefix=QRTZ_
#配置quartz数据库,优势就是可以和业务数据库分开,相当于配置了两个数据库
org.quartz.jobStore.dataSource=myDS
org.quartz.dataSource.myDS.driver=com.mysql.cj.jdbc.Driver
org.quartz.dataSource.myDS.URL=jdbc:mysql://localhost:3307/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
org.quartz.dataSource.myDS.user=root
org.quartz.dataSource.myDS.password=root
#最大连接数
org.quartz.dataSource.myDS.maxConnections=5

配置quartz.config:

@Configuration
public class SchedulerConfig {
    @Bean(name = "SchedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setAutoStartup(true);
        factory.setStartupDelay(5);//延时5秒启动
        factory.setQuartzProperties(quartzProperties());
        return factory;
    }
    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        //这个东西如果不配置的话,quartz有自己默认的配置文件
        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }
    /*
     * 通过SchedulerFactoryBean获取Scheduler
     */
    @Bean(name = "Scheduler")
    public Scheduler scheduler() throws IOException {
        return schedulerFactoryBean().getScheduler();
    }

}

编写quartz的接口:

@RestController
public class JobController {
    private final static Logger LOGGER = LoggerFactory.getLogger(JobController.class);
    private final String baseuri = "/job";
    @Autowired
    @Qualifier("Scheduler")
    private Scheduler scheduler;
    @Autowired
    private JobService jobService;

    /**
     * 新增任务
     *
     * @param quartz
     * @return
     */
    @RequestMapping(value = baseuri + "/addschedule")
    public Result save(QuartzBean quartz) throws Exception {
        LOGGER.info("新增任务");
        int i = 100 / 0;
        if (quartz.getOldJobGroup() != null) {
            JobKey key = new JobKey(quartz.getOldJobName(), quartz.getOldJobGroup());
            scheduler.deleteJob(key);
        }
        //获取.class
        Class cls = Class.forName(quartz.getJobClassName());
        cls.newInstance();
        //创建jobdetail
        JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(),
                quartz.getJobGroup())
                //设置参数
                //.usingJobData("aa", "ceshi")
                //描述
                .withDescription(quartz.getDescription())
                .build();
        // 使用cron表达式
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression());
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger" + quartz.getJobName(), quartz.getJobGroup())
                .startNow()
                .withSchedule(cronScheduleBuilder)
                .build();
        //交由Scheduler安排触发
        scheduler.scheduleJob(job, trigger);
        return new Result("200", "", null);
    }

    /**
     * 获取任务列表
     *
     * @param name
     * @return
     */
    @RequestMapping(value = baseuri + "/getlist4schedule")
    public Result list(String name) {
        LOGGER.info("任务列表");
        List<QuartzBean> list = jobService.listQuartzBean(name);
        return new Result("200", "", list);
    }

    /**
     * 立即执行
     *
     * @param quartz
     * @return
     */
    @RequestMapping(value = baseuri + "/doschedule")
    public Result trigger(QuartzBean quartz) throws Exception {
        LOGGER.info("立即执行");
        JobKey key = new JobKey(quartz.getJobName(), quartz.getJobGroup());
        scheduler.triggerJob(key);
        return new Result("200", "", null);
    }

    /**
     * 暂停任务
     *
     * @param quartz
     * @return
     */
    @RequestMapping(value = baseuri + "/pauseschedule")
    public Result pause(QuartzBean quartz) throws Exception {
        LOGGER.info("停止任务");
        JobKey key = new JobKey(quartz.getJobName(), quartz.getJobGroup());
        scheduler.pauseJob(key);
        return new Result("200", "", null);
    }

    /**
     * 从暂停中恢复过来
     *
     * @param quartz
     * @return
     */
    @RequestMapping(value = baseuri + "/recoverschedule")
    public Result resume(QuartzBean quartz) throws Exception {
        LOGGER.info("恢复任务");
        JobKey key = new JobKey(quartz.getJobName(), quartz.getJobGroup());
        scheduler.resumeJob(key);
        return new Result("200", "", null);
    }

    /**
     * 删除任务
     *
     * @param quartz
     * @return
     */
    @RequestMapping(value = baseuri + "/deleteschedule")
    public Result remove(QuartzBean quartz) throws Exception {
        LOGGER.info("删除任务");
        TriggerKey triggerKey = TriggerKey.triggerKey(quartz.getJobName(), quartz.getJobGroup());
        // 停止触发器
        scheduler.pauseTrigger(triggerKey);
        // 移除触发器
        scheduler.unscheduleJob(triggerKey);
        // 删除任务
        scheduler.deleteJob(JobKey.jobKey(quartz.getJobName(), quartz.getJobGroup()));
        System.out.println("removeJob:" + JobKey.jobKey(quartz.getJobName()));
        return new Result("200", "", null);
    }
}

编写接口错误拦截返回:

@ControllerAdvice
public class ErrorController {
    private final static Logger logger = LoggerFactory.getLogger(ErrorController.class);
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result error(Throwable throwable) {
        System.out.println("aaa");
        logger.error(throwable.toString());
        return new Result("500", throwable.toString(), null);
    }
}

疑问:

以上代码就能实现springboot对quartz的管理,增删改查、立即执行、暂停、恢复等操作,但是任有不少疑问。。。

1、为什么我们并没有对数据库进行操作,数据库中就有了quartz的数据?

2、 我们配置了threadCount为5,那么如果有5个任务还在执行的时候触发了第六个任务会怎么样?

3、如果任务刚执行完,把系统时间修改为任务触发时间之前,那相同时间还会再触发一次吗?

解决:https://blog.csdn.net/tuesdayma/article/details/81563011

猜你喜欢

转载自blog.csdn.net/tuesdayma/article/details/81538270