定时任务组件、作业调度程序之Quartz

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 定时任务组件、作业调度程序之Quartz,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

Quartz

Quartz是功能强大的开源作业调度库,几乎可以集成到任何Java应用程序中。

官网: http://www.quartz-scheduler.org/

文档: http://www.quartz-scheduler.org/documentation/

GitHub: https://github.com/quartz-scheduler/quartz

核心API

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Scheduler:任务调度器,使任务和触发器关联,统一进行任务的调度

StdSchedulerFactory:任务调度器工厂,可以创建Scheduler对象

JobDetail:任务对象

JobBuilder:任务构建器,用于创建JobDetail对象

Trigger:触发器对象

TriggerBuilder:触发器构建器,用于创建Trigger对象

JobExecutionContext:任务执行的上下文对象,通过此对象可以获取当前执行任务的相关信息,例如JobDetailTrigger对象都可以获取到

JobDataMap:保存任务实例的状态信息

RAMJobStore:此类实现了一个利用RAM作为其存储设备的JobStore,访问速度极快,但是数据却易失,如果需要在程序关闭之前保持真正的持久性,则不应使用此JobStore

JobStoreTX:通过JDBC将所有数据保存在数据库中

基本使用

添加依赖

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.3.2</version>
        </dependency>

自定义Job类实现Job接口

@Slf4j
public class MyJob implements Job {

    public MyJob() {
        log.info("public MyJob() ....");
    }

    /**
     * 执行方法
     *
     * @param jobExecutionContext 任务执行上下文对象
     */
    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
        log.info("自定义Job执行: {}", formatter.format(now));


        // Quartz提供了相应方法可以在创建任务时设置参数,并且通过提供的上下文对象(JobExecutionContext)来获取参数
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        Set<Map.Entry<String, Object>> entries = jobDataMap.entrySet();
        entries.forEach((entry) -> {
            String key = entry.getKey();
            Object value = entry.getValue();
            log.info("key : {}, value : {}", key, value);
        });
    }
}

启动任务调度

 public static void main(String[] args) {
        try {
            //创建调度器
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

            //创建任务实例
            JobDetail jobDetail = JobBuilder.newJob(MyJob.class).
                    withIdentity("JobDetail_MyJob","myGroup").
                    build();

            //设置参数,在定时任务执行时可以动态获取参数
            jobDetail.getJobDataMap().put("key1", "value1");
            jobDetail.getJobDataMap().put("key2", "value2");


            //构建cron表达式
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
            //构建简单的表达式
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever();

            //创建触发器Trigger
            Trigger trigger = TriggerBuilder.newTrigger().
                    withIdentity("Trigger_MyJob","myGroup").
//                  withSchedule(simpleScheduleBuilder).
        withSchedule(cronScheduleBuilder).
                    build();

            //触发器和任务关联
            scheduler.scheduleJob(jobDetail, trigger);

            //启动任务调度器
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
16:29:35.012 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.JobDetail_MyJob', class=cn.ybzy.demo.job.MyJob
16:29:35.012 [DefaultQuartzScheduler_QuartzSchedulerThread] INFO cn.ybzy.demo.job.MyJob - public MyJob() ....
16:29:35.012 [DefaultQuartzScheduler_Worker-2] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.JobDetail_MyJob
16:29:35.012 [DefaultQuartzScheduler_Worker-2] INFO cn.ybzy.demo.job.MyJob - 自定义Job执行: 2021-12-21 04:29:35
16:29:35.012 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:29:35.012 [DefaultQuartzScheduler_Worker-2] INFO cn.ybzy.demo.job.MyJob - key : key1, value : value1
16:29:35.012 [DefaultQuartzScheduler_Worker-2] INFO cn.ybzy.demo.job.MyJob - key : key2, value : value2

Spring集成Quartz

定义任务类

//@Component  声明bean对象
public class MyJob {
    public void run(){
        System.out.println("HHello Quartz");
    }
}

配置Quartz

创建application-jobs.xml配置Quartz参数及任务对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans.xsd
                  http://www.springframework.org/schema/mvc
                  http://www.springframework.org/schema/mvc/spring-mvc.xsd
                  http://www.springframework.org/schema/context
                  http://www.springframework.org/schema/context/spring-context.xsd">

    <!--自定义任务对象-->
    <bean id="jobDemo" class="cn.ybzy.demo.job.MyJob"></bean>

    <!--任务详细对象-->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="jobDemo"/>
        <property name="targetMethod" value="run"/>
    </bean>

    <!--触发器:通过cron表达式指定执行的时间-->
    <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="jobDetail"/>
        <property name="cronExpression">
            <value>0/10 * * * * ?</value>
        </property>
    </bean>

    <!--任务调度工厂对象-->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="trigger"></ref>
            </list>
        </property>
    </bean>
</beans>

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:application-jobs.xml</param-value>
    </context-param>
</web-app>

动态定时任务

通过JobStoreTX对象将任务相关信息保存在数据库中,这样就可以避免服务重启后任务信息丢失的问题。同时此种方式还支持动态定时任务,例如动态添加定时任务、暂停定时任务、删除定时任务等操作。

添加依赖

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

导入数据表

Quartz针对不同的数据库提供了不同的sql脚本文件

https://github.com/quartz-scheduler/quartz/blob/master/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql

在这里插入图片描述

MySQL数据库,Quartz提供了一套数据模型(共11张表)用于保存定时任务相关信息

配置application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://IP:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC

定时任务配置类

编写定时任务配置类ScheduleConfig

@Configuration
public class ScheduleConfig {
    /**
     * 调度器工厂,用于创建调度器对象Scheduler
     *
     * @param dataSource
     * @return
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);

        //quartz参数
        Properties prop = new Properties();
        prop.put("org.quartz.scheduler.instanceName", "myInstanceName");
        prop.put("org.quartz.scheduler.instanceId", "AUTO");

        //线程池配置
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "20");
        prop.put("org.quartz.threadPool.threadPriority", "5");

        //JobStore配置
        prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");

        //集群配置
        prop.put("org.quartz.jobStore.isClustered", "true");
        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");

        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
        prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
        factory.setQuartzProperties(prop);

        factory.setSchedulerName("mySchedulerName");

        //延时启动
        factory.setStartupDelay(3);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
        factory.setOverwriteExistingJobs(true);

        //设置自动启动,默认为true
        factory.setAutoStartup(true);
        return factory;
    }
}

自定义Job类

@Slf4j
public class MyJob extends QuartzJobBean {

    public MyJob() {
        log.info("public MyJob() ....");
    }

    /**
     * 任务触发时执行此方法
     *
     * @param jobExecutionContext
     */
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) {
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
        log.info("自定义Job执行: {}", formatter.format(now));

        Object uid = jobExecutionContext.getJobDetail().getJobDataMap().get("uid");
        log.info("uid: {}", uid);
    }
}

实现各类定时任务

@RestController
@RequestMapping("/quartz")
public class QuartzController {

    @Autowired
    private Scheduler scheduler;

    /**
     * 添加定时任务
     *
     * @param cronExpression
     * @return
     */
    @PostMapping
    public String save(String cronExpression) throws Exception {
        String uid = UUID.randomUUID().toString();
        //构建job信息
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity(uid).build();
        jobDetail.getJobDataMap().put("uid", uid);
        //表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression)
                .withMisfireHandlingInstructionDoNothing();

        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(uid).withSchedule(scheduleBuilder).build();
        //关联任务和触发器
        scheduler.scheduleJob(jobDetail, trigger);
        return "success";
    }

    /**
     * 暂停定时任务
     *
     * @param uid
     * @return
     */
    @PutMapping("/pause/{uid}")
    public String pause(@PathVariable String uid) throws Exception {
        JobKey jobKey = JobKey.jobKey(uid);
        scheduler.pauseJob(jobKey);
        return "success";
    }

    /**
     * 恢复定时任务
     *
     * @param uid
     * @return
     */
    @PutMapping("/resume/{uid}")
    public String resume(@PathVariable String uid) throws Exception {
        JobKey jobKey = JobKey.jobKey(uid);
        scheduler.resumeJob(jobKey);
        return "success";
    }

    /**
     * 删除定时任务
     *
     * @param uid
     * @return
     */
    @DeleteMapping
    public String delete(String uid) throws Exception {
        JobKey jobKey = JobKey.jobKey(uid);
        scheduler.deleteJob(jobKey);
        return "success";
    }

    /**
     * 立即执行定时任务
     *
     * @param uid
     * @return
     */
    @PutMapping("/run/{uid}")
    public String run(@PathVariable String uid) throws Exception {
        JobKey jobKey = JobKey.jobKey(uid);
        scheduler.triggerJob(jobKey);
        return "success";
    }

    /**
     * 更新定时任务
     *
     * @param uid
     * @param cronExpression
     * @return
     * @throws Exception
     */
    @PutMapping
    public String update(String uid, String cronExpression) throws Exception {
        TriggerKey triggerKey = TriggerKey.triggerKey(uid);
        //表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression)
                .withMisfireHandlingInstructionDoNothing();

        //获取触发器对象
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

        //按新的cronExpression表达式重新构建trigger
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

        scheduler.rescheduleJob(triggerKey, trigger);
        return "success";
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/136996.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!