ShedLock配合使用SchedulingConfigurer实现数据库控制定时任务

2 篇文章 0 订阅
1 篇文章 0 订阅

简单介绍

1.ShedLock是一个定时任务锁,并不是定时任务调度工具,更不是分布式任务调度程序。但是可以解决定时任务在多台服务器上重复执行的情况。

2.由spring boot提供的一个定时任务接口,实现该接口的bean,会在所有bean初始化结束后,调用configureTasks来配置定时任务。

3. 注意

  1. ShedLock不是任务调度工具,只是一个锁。需要任务调度工具要使用其他方法。
  2. 配合SchedulingConfigurer可以实现可控的定时任务,但并不是实时的控制,需要下次执行才会更改定时任务。如果有业务需要,可以通过判断参数手动执行定时任务,但不执行实际业务代码。

ShedLock

参考文档:https://github.com/lukas-krecan/ShedLock
项目很简单,总共分3步。

  1. 根据需要导入对应的项目,具体可以看github上的文章
<!-- 必须--> 
<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-spring</artifactId>
    <version>4.20.0</version>
</dependency>
<!-- redis --> 
<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-redis-spring</artifactId>
    <version>4.20.0</version>
</dependency>
  1. 写好配置类

@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "10m")
class MySpringConfiguration {

    @Bean
    public LockProvider lockProvider(RedisConnectionFactory connectionFactory) {
        return new RedisLockProvider(connectionFactory, ENV);
    }

}
  1. 写定时任务,简单的spring boot定时任务实现
@Component
public class SpringBootLockTask {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //定时器时间配置 cron表达式
    @Scheduled(cron = "0 0/1 * * * ? ")
    //标识使用分布式锁
    @SchedulerLock(name = "springBootLockTask1", lockAtMostFor = "50s", lockAtLeastFor = "50s")
    public void expireOrderSchedule() {
        logger.info("执行方法springBootLockTask1");
        try {
            Thread.sleep(5 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("执行方法springBootLockTask1 ------------- 结束");
    }

    //定时器时间配置 cron表达式
    @Scheduled(cron = "0 0/1 * * * ? ")
    //标识使用分布式锁
    @SchedulerLock(name = "springBootLockTask2", lockAtMostFor = "50s", lockAtLeastFor = "50s")
    public void expireOrderSchedule2() {
        logger.info("执行方法springBootLockTask2");
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("执行方法springBootLockTask2 ------------ 结束");
    }

}

完成,在启动项目后会开始分别执行两个定时任务,当两个定时任务的@SchedulerLock的注解的name相同时,expireOrderSchedule1和expireOrderSchedule2只能执行一个。

SchedulingConfigurer

  1. 实现接口,写一个公共方法,后面的定时任务可以直接继承该类
@Configuration
@EnableScheduling
public abstract class ConfigurerScheduling implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(
                //执行定时任务 业务代码,可以在这里判断是否执行业务代码
                this::execute,
                //设置cron
                triggerContext -> {
                    CronTrigger trigger = new CronTrigger(getCron());
                    return trigger.nextExecutionTime(triggerContext);
                }
        );
    }

    protected abstract void execute();

    protected abstract String getCron();
}
  1. 实现抽象方法
    在项目启动后,定时任务就会自动跑execute()里的内容。
@Configuration
public class TestTask extends ConfigurerScheduling {

    @Override
    protected void execute() {
        System.out.println("TestTask定时任务开始了");
    }

    @Override
    protected String getCron() {
        //可以从数据库拿数据
        return "0 0/1 * * * ? ";
    }
}

配合使用

定时任务
@Component
public class TestTask extends ConfigurerScheduling {

    @Override
    @SchedulerLock(name = "TestTask", lockAtMostFor = "50s", lockAtLeastFor = "50s")
    protected void execute() {
        //业务代码
        System.out.println("TestTask定时任务开始了");
    }
    
    @Override
    protected String getName() {
        //获取bean名称
        return "testTask";
    }

    @Override
    protected String getCron() {
        //可以从数据库拿数据
        return "0 0/1 * * * ? ";
    }
}
抽象类,公共类

注意:因为spring boot代理的问题,这里只能再次获取bean,然后再调用execute()方法才有效,否则SchedulerLock注解失效且不会有异常

@Configuration
@EnableScheduling
public abstract class ConfigurerScheduling implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(
                //执行定时任务 业务代码,可以在这里判断是否执行业务代码
                this::executeToDo,
                //设置cron
                triggerContext -> {
                    CronTrigger trigger = new CronTrigger(getCron());
                    return trigger.nextExecutionTime(triggerContext);
                }
        );
    }

    private void executeToDo() {
        // 因为spring boot代理的问题,这里只能再次获取bean,然后再调用execute()方法才有效,否则SchedulerLock注解失效且不会有异常
        // ApplicationContext.getBean(); 通过getName获取bean方法
        // execute(); 使用获取到的bean调用execute()方法
        ConfigurerScheduling bean = (ConfigurerScheduling) SpringUtils.getBean(getName());
        bean.execute();
    }

    protected abstract void execute();

    protected abstract String getCron();

    protected abstract String getName();

}
SpringUtils类,用于获取spring boot的bean
@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContextParam) throws BeansException {
        applicationContext = applicationContextParam;
    }

    //通过名称获取bean
    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }

    //通过类型获取bean
    public <T> T getBean(Class<T> tClass) {
        return applicationContext.getBean(tClass);
    }

    //通过类型和名称获取bean
    public static <T> T getBean(String beanName, Class<T> tClass) {
        return applicationContext.getBean(beanName, tClass);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值