SpringBoot如何实现动态的定时任务

15 篇文章 0 订阅
3 篇文章 0 订阅

一、介绍

SpringBoot项目中,创建定时任务除了使用@Scheduled 注解外,还可以使用 SchedulingConfigurer
@Schedule 注解有一个缺点,其定时的时间不能动态的改变,而基于 SchedulingConfigurer 接口的方式可以做到动态的定时任务。

二、依赖

因为这种方式实现动态定时任务需要用到数据库,所以需要mysql驱动jpa依赖,以及lombok测试类依赖。

<!--继承SpringBoot父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/>
    </parent>


		<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
        <!--        SpringBoot测试类-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--	jpa		-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--	mysql驱动		-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

三、定时任务配置类ScheduledConfig

我们不使用@Scheduled注解的形式,采用实现SchedulingConfigurer接口的形式来实现动态定时任务。

原理

@FunctionalInterface
public interface SchedulingConfigurer {
    void configureTasks(ScheduledTaskRegistrar var1);
}

实现SchedulingConfigurer接口需要重写configureTasks方法。
然后使用ScheduledTaskRegistrar调用addTriggerTask方法。
使用addTriggerTask方法就是增加一个触发任务。

public void addTriggerTask(Runnable task, Trigger trigger) {
        this.addTriggerTask(new TriggerTask(task, trigger));
    }

这个方法的参数有两个:
第一个参数task,简单解释就是我们要执行的定时时间,这个事件要实现Runnable接口,就是创建一个线程。
第二个参数trigger,就是触发器,点进Trigger这个类,

public interface Trigger {
    @Nullable
    Date nextExecutionTime(TriggerContext var1);
}

nextExecutionTime就是下一次执行的时间,所以我们可以发现这个Trigger的作用就是控制时间下一次执行的时间。
Trigger类这个就是我们实现动态控制定时任务的关键!
另外CronTrigger类实现了Trigger类,
所以我们在这里查询数据库中cron表达式,赋值到这里。这样我们通过修改数据库中的cron表达式,就可以达到动态的控制定时任务的执行了。

完整的配置类代码

package com.lsh.config;

import com.lsh.entity.SpringScheduledCron;
import com.lsh.respsitory.SpringScheduledCronRepository;
import com.lsh.task.DynamicPrintTask3;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * @author :LiuShihao
 * @date :Created in 2020/8/24 4:36 下午
 * @desc :查询数据库cron表达式  动态切换cron表达式
 *
 */
@Slf4j
@Configuration
public class ScheduledConfig implements SchedulingConfigurer {
    @Autowired
    private SpringScheduledCronRepository cronRepository;
	//注入我们的定时任务类
    @Autowired
    DynamicPrintTask task;
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        
            //可以通过改变数据库数据进而实现动态改变执行周期
            /**
             *
             * public void addTriggerTask(Runnable task, Trigger trigger) {
             *      this.addTriggerTask(new TriggerTask(task, trigger));
             *     }
             * 使用这个方法会增加一个触发任务 :即  !这个定时任务的下一次执行时间!
             * 参数:Runnable    一个事件
             * 参数:Trigger     一个触发器
             * public interface Trigger {
             *     @Nullable
             *     Date nextExecutionTime(TriggerContext var1);   下一次执行时间
             * }
             */
            taskRegistrar.addTriggerTask(((Runnable) task3),
                    triggerContext -> {
                        //查询数据库  获得该类的cron表达式
                        String cronExpression = cronRepository.findSpringScheduledCronByCronKey(task3.getClass().getName()).getCronExpression();
                        log.info("cronRepository.findByCronExpression():"+cronExpression);
                        // CronTrigger实现了Trigger
                        return new CronTrigger(cronExpression).nextExecutionTime(triggerContext);
                    }
            );
        
    }
    @Bean
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(10);
    }
}

四、定时任务类

我们的定时任务类必须实现Runnable接口!

package com.lsh.task;

import com.lsh.respsitory.SpringScheduledCronRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author :LiuShihao
 * @date :Created in 2020/8/24 4:53 下午
 * @desc :
 */
@Component
public class DynamicPrintTask implements Runnable {
    public static Boolean isRun = false;
    @Autowired
    SpringScheduledCronRepository springScheduledCronRepository;

    @Override
    public void run() {
        if (isRun) return;
        isRun = true;
        //通过类名获得表达式信息  判断状态是否可用 1:正常   2:停用  如果不可用直接返回
        //this.getClass().getName()  获得当前类名   com.lsh.task.DynamicPrintTask3
        Integer status = springScheduledCronRepository.findSpringScheduledCronByCronKey(this.getClass().getName()).getStatus();
        if (2 == status){
            return;
        }
        System.out.println("-----=====定时任务3:"+ LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        isRun = false;
    }
}

五、JPA

package com.lsh.respsitory;

import com.lsh.entity.SpringScheduledCron;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author :LiuShihao
 * @date :Created in 2020/8/24 4:58 下午
 * @desc :
 */

public interface SpringScheduledCronRepository extends JpaRepository<SpringScheduledCron, Integer> {
    //根据CronKey查找表达式
    SpringScheduledCron findSpringScheduledCronByCronKey(String CronKey);
}

六、实体类

package com.lsh.entity;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

/**
 * @author :LiuShihao
 * @date :Created in 2020/8/24 5:01 下午
 * @desc :
 */
@Data
@Entity(name = "spring_scheduled_cron")
public class SpringScheduledCron {
    @Id
    @Column(name = "cron_id")
    private Integer cronId;
    @Column(name = "cron_key", unique = true)
    private String cronKey;
    @Column(name = "cron_expression")
    private String cronExpression;
    @Column(name = "task_explain")
    private String taskExplain;
    private Integer status;
}

sql语句

CREATE TABLE `spring_scheduled_cron` (
  `cron_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `cron_key` varchar(128) NOT NULL COMMENT '定时任务完整类名',
  `cron_expression` varchar(20) NOT NULL COMMENT 'cron表达式',
  `task_explain` varchar(50) NOT NULL DEFAULT '' COMMENT '任务描述',
  `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态,1:正常;2:停用',
  PRIMARY KEY (`cron_id`),
  UNIQUE KEY `cron_key` (`cron_key`),
  UNIQUE KEY `cron_key_unique_idx` (`cron_key`)
) 

七、yml配置文件

spring:
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/day27
    username: root
    password: 123456
  jpa:
    show-sql: true
server:
  port: 8089

八、主启动类

@SpringBootApplication
@EnableScheduling
public class TimerTaskApplication {
    public static void main(String[] args) {
        SpringApplication.run(TimerTaskApplication.class);
    }
}

九、启动测试

表数据:
在这里插入图片描述
在这里插入图片描述

缺点

不过这种方式也有缺点,就是增加了数据库的压力,长时间占着数据库的连接,查询基数大。
我们可以引入缓存来减轻数据库压力,减少内存消耗
缓存依赖:

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

另外除了引入缓存,还用另外一种方式来解决这个问题,就是使用MQ延时队列也可以实现动态的控制定时任务使用MQ延时队列来解决动态定时任务问题

  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
Spring Boot通过@EnableScheduling注解来开启定时任务的功能。下面是实现动态定时任务的步骤: 1. 首先,在你的Spring Boot应用的主类上添加@EnableScheduling注解,启用定时任务的支持。例如: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } } ``` 2. 接下来,在需要执行定时任务的方法上添加@Scheduled注解,并设置定时任务的执行规则。例如,我们可以使用cron表达式来定义定时任务的执行时间。以下是一个示例: ```java import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class MyScheduledTask { @Scheduled(cron = "0 0/5 * * * *") // 每5分钟执行一次 public void doSomething() { // 定时任务要执行的操作 } } ``` 3. 现在,当应用启动后,定时任务会按照定义的规则自动执行。 如果你想在运行时动态地修改定时任务的执行规则,可以借助Spring的ScheduledTaskRegistrar类。可以在应用程序中注入ScheduledTaskRegistrar对象,然后使用其方法来注册、取消和修改定时任务。这样你就可以实现动态定时任务调度了。 希望这个回答对你有帮助!如果你还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liu_Shihao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值