任务调度框架

1、quartz

1.1 概述

Quartz是OpenSymphony开源组织在Job scheduling领域的一个开源项目,由Java开发,可以用来执行定时任务,类似于java.util.Timer。Quartz是功能强大的开源作业调度库,几乎可以集成到任何Java应用程序中。Quartz包含许多企业级功能,例如对JTA事务和集群的支持。Quartz作为定时任务组件,既可以单独使用,也可以整合Spring使用。

1.2 核心

1.2.1 api

在这里插入图片描述

Scheduler:任务调度器,使任务和触发器关联,统一进行任务的调度
StdSchedulerFactory:任务调度器工厂,可以创建Scheduler对象
JobDetail:任务对象
JobBuilder:任务构建器,用于创建JobDetail对象
Trigger:触发器对象
TriggerBuilder:触发器构建器,用于创建Trigger对象
JobExecutionContext:任务执行的上下文对象,通过此对象可以获取当前执行任务的相关信息,例如JobDetail、Trigger对象都可以获取到
JobDataMap:保存任务实例的状态信息
RAMJobStore:此类实现了一个利用RAM作为其存储设备的JobStore,访问速度极快,但是数据却易失,如果需要在程序关闭之前保持真正的持久性,则不应使用此JobStore
JobStoreTX:通过JDBC将所有数据保存在数据库中

1.2.2 存储

  • JobStoreTX

通过上下文对象JobExecutionContext可以看到任务的存储是通过RAMJobStore实现的,这种方式的任务信息是保存在内存中的,如果服务重启后则任务信息都会丢失。

  • 数据模型

Quartz官方提供了一套数据模型(共11张表)用于保存定时任务相关信息,建表脚本:
在这里插入图片描述

1.3 示例

  • 依赖
 <!--quartz 定时任务-->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.3.0</version>
        </dependency>
  • 消除debug日志
resource中配置logback.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

</configuration>
  • job
// 自定义job
public class HelloJob implements Job {

    public HelloJob() {
        System.out.println("hellojob被创建了");
    }

    /**
     * 当任务触发时执行此方法
     * @param context
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        Set<Map.Entry<String, Object>> entries = jobDataMap.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }

        System.out.println("自定义job执行时间"+ LocalDateTime.now());
    }
}
  • scheduler,trigger
public class HelloJobMain {
    public static void main(String[] args) throws SchedulerException {

        //根据调度器工厂创建任务调度器实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        //通过任务构建器对象创建任务实例
        JobDetail jobdetail = JobBuilder.newJob(HelloJob.class).withIdentity("myjobdetail").build();
        JobDataMap jobDataMap = jobdetail.getJobDataMap();
        jobDataMap.put("key1","value1");
        jobDataMap.put("key2","value2");

        //通过触发器构建对象创建触发器实例
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("mytrigger")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever())
                .build();

        // 关联任务实例和触发器实例
        scheduler.scheduleJob(jobdetail,trigger);
        scheduler.start();
    }
}

1.4 springboot集成

  • 依赖
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3.1</version>
        </dependency>

        <!--quartz 定时任务-->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
            <exclusions>
                <exclusion>
                    <groupId>com.mchange</groupId>
                    <artifactId>c3p0</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.zaxxer</groupId>
                    <artifactId>HikariCP-java6</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.3.0</version>
        </dependency>


        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>
        </plugins>
    </build>
  • 配置类
/**
 * 定时任务配置
 *
 * @author
 */
@Configuration
public class ScheduleConfig {
    //调度器工厂,用于创建调度器对象Scheduler
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);

        //quartz参数
        Properties prop = new Properties();
        prop.put("org.quartz.scheduler.instanceName", "WitlinkedScheduler");
        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("pdScheduler");
        //延时启动
        factory.setStartupDelay(3);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
        factory.setOverwriteExistingJobs(true);
        //设置自动启动,默认为true
        factory.setAutoStartup(true);
        return factory;
    }
}




@Slf4j
@Configuration
@EnableSwagger2
public class ConfigurationSupport extends WebMvcConfigurationSupport {
    @Bean
    public Docket createRestApi() {
        // 文档类型
        return new Docket(DocumentationType.SWAGGER_2)
                // 创建api的基本信息
                .apiInfo(apiInfo())
                // 选择哪些接口去暴露
                .select()
                // 扫描的包
                .apis(RequestHandlerSelectors.basePackage("com.xing.quartz.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Swagger文档")
                .version("1.0")
                .build();
    }

    /**
     * 防止@EnableMvc把默认的静态资源路径覆盖了,手动设置的方式
     *
     * @param registry
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 解决静态资源无法访问
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        // 解决swagger无法访问
        registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        // 解决swagger的js文件无法访问
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}
  • controller

@RestController
@RequestMapping("/api/quartzController")
public class QuartzController {

    @Autowired
    private Scheduler scheduler;

    /**
     * 添加定时任务
     * @param jobId
     * @param cronExpression
     * @return
     * @throws SchedulerException
     */
    @PostMapping("/save")
    @ApiOperation(value = "添加定时任务")
    public String save(String jobId, String cronExpression) throws SchedulerException {

        //创建任务实例
        JobDetail jobDetail = JobBuilder.newJob(JobOne.class).withIdentity(jobId).build();
        jobDetail.getJobDataMap().put("jobId",jobId);

        //创建触发器对象
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(jobId)
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing())
                .build();

        scheduler.scheduleJob(jobDetail, trigger);
        return "OK";
    }

    /**
     * 暂停定时任务
     * @param jobId
     * @return
     * @throws SchedulerException
     */
    @PutMapping("/pause/{jobId}")
    @ApiOperation(value ="暂停定时任务")
    public String pause(@PathVariable("jobId") String jobId) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobId);
        scheduler.pauseJob(jobKey);
        return "OK";
    }

    /**
     * 暂停所有定时任务
     * @return
     * @throws SchedulerException
     */
    @PutMapping("/pauseAll")
    @ApiOperation(value ="暂停所有定时任务")
    public String pauseAll() throws SchedulerException {
        scheduler.pauseAll();
        return "OK";
    }

    /**
     * 恢复定时任务
     * @param jobId
     * @return
     * @throws SchedulerException
     */
    @PutMapping("/resume/{jobId}")
    @ApiOperation(value ="恢复定时任务")
    public String resume(@PathVariable("jobId") String jobId) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobId);
        scheduler.resumeJob(jobKey);
        return "OK";
    }

    /**
     * 恢复所有定时任务
     * @return
     * @throws SchedulerException
     */
    @PutMapping("/resumeAll")
    @ApiOperation(value ="恢复所有定时任务")
    public String resumeAll() throws SchedulerException {
        scheduler.resumeAll();
        return "OK";
    }



    /**
     * 删除定时任务
     * @param jobId
     * @return
     * @throws SchedulerException
     */
    @DeleteMapping("/delete/{jobId}")
    @ApiOperation(value ="删除定时任务")
    public String delete(@PathVariable("jobId") String jobId) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobId);
        scheduler.deleteJob(jobKey);
        return "OK";
    }

    /**
     * 删除所有定时任务
     * @return
     * @throws SchedulerException
     */
    @DeleteMapping("/delete")
    @ApiOperation(value ="删除所有定时任务")
    public String deleteAll() throws SchedulerException {
        return "OK";
    }

    /**
     * 立即执行定时任务
     * @return
     * @throws SchedulerException
     */
    @PutMapping("/run/{jobId}")
    @ApiOperation(value ="立即执行定时任务")
    public String run(@PathVariable("jobId")String jobId) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobId);
        scheduler.triggerJob(jobKey);
        return "OK";
    }

    @PutMapping("/update/{jobId}")
    @ApiOperation(value = "更新定时任务")
    public String update(@PathVariable()String jobId,String cronExpression) throws SchedulerException {
        //触发器唯一标识
        TriggerKey triggerKey = TriggerKey.triggerKey(jobId);

        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();

        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        trigger = trigger.getTriggerBuilder().withIdentity(jobId).withSchedule(cronScheduleBuilder).build();

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

    @GetMapping("/findAll")
    @ApiOperation(value = "查看所有任务")
    public Map<String,Object> findAll() throws SchedulerException {
        HashMap<String, Object> map = new HashMap<>();

        List<String> triggerGroupNames = scheduler.getTriggerGroupNames();
        //再获取Scheduler下的所有group
        for (String triggerGroupName : triggerGroupNames) {
            //组装group的匹配,为了模糊获取所有的triggerKey或者jobKey
            GroupMatcher groupMatcher = GroupMatcher.groupEquals(triggerGroupName);
            Set<TriggerKey> triggerKeys = scheduler.getTriggerKeys(groupMatcher);
            for (TriggerKey triggerKey : triggerKeys) {
                Trigger trigger = scheduler.getTrigger(triggerKey);
                JobKey jobKey = trigger.getJobKey();
                map.put(triggerKey.getName(),jobKey);
            }
        }
        return map;
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值