详解SpringBoot 创建定时任务(配合数据库动态执行)

先来介绍一下 SpringBoot 这个框架。SpringBoot 是一款基于 Spring 框架的快速开发框架,能够帮助开发者快速搭建 Spring 应用,极大地提高了开发效率。在 SpringBoot 中,我们可以非常简单地创建定时任务并进行动态执行,下面是详解 SpringBoot 创建定时任务(配合数据库动态执行)的攻略:

一、引入相关依赖

在创建我们的 SpringBoot 项目时,需要在 pom.xml 中加上以下依赖:

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

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

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

其中,spring-boot-starter-data-jdbc 是 SpringBoot 自带的 JDBC 数据库框架,spring-boot-starter-quartz 是帮助我们管理定时任务的框架,quartz-jobs 是 Quartz 任务调度框架的依赖。

二、编写定时任务

下面为一个简单的固定执行时间的定时任务,代码如下:

@Component
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("Hello World!");
    }
}

@Configuration
public class QuartzConfig {
    @Bean
    public JobDetail helloJobDetail() {
        return JobBuilder.newJob(HelloJob.class).withIdentity("helloJob").storeDurably().build();
    }

    @Bean
    public Trigger helloJobTrigger() {
        return TriggerBuilder.newTrigger().forJob(helloJobDetail()).withIdentity("helloJobTrigger")
                .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setJobDetails(helloJobDetail());
        factory.setTriggers(helloJobTrigger());
        return factory;
    }
}

HelloJob 实现了 Quartz 的 Job 接口,我们可以在 execute 方法中编写我们的业务逻辑。QuartzConfig 配置类中定义了 helloJobDetail 和 helloJobTrigger 两个 Bean,用于定义 Job 和 Trigger 的具体信息,并指定在何时执行。同时,我们在 schedulerFactoryBean 中通过设置 JobDetails 和 Triggers 来将 Job 和 Trigger 关联起来。在 Cron 表达式中设置定时任务执行时间,这里我们设置的是每 5 秒执行一次。

在以上代码中,我们使用了 Quartz 的 CronScheduleBuilder 类来设置定时任务的执行时间,以下是几个常用的 Cron 表达式:

  • "0/5 * * * * ?":每 5 秒执行一次
  • "0 0 12 * * ?":每天中午 12 点执行
  • "0 15 10 ? * *":每天上午 10:15 执行
  • "0 15 10 * * ?":每天上午 10:15 执行
  • "0 15 10 * * ? *":每天上午 10:15 执行
  • "0 15 10 * * ? 2019":2019 年的每天上午 10:15 执行

三、动态执行任务

接下来,我们将了解如何从数据库中动态获取任务定时时间并执行任务。

首先,我们需要定义一个接口,用于定义定时任务的服务方法:

public interface ScheduledTaskService {
    /**
     * 获取所有的数据库中的定时任务
     * @return
     */
    List<ScheduledTask> getAllScheduledTask();

    /**
     * 根据定时任务 ID 执行定时任务
     * @param scheduledTaskId
     */
    void executeTask(Integer scheduledTaskId);
}

ScheduledTaskService 接口中定义了 getAllScheduledTask 和 executeTask 两个方法,用于获取数据库中的定时任务和执行定时任务,具体实现方式如下:

@Service
public class ScheduledTaskServiceImpl implements ScheduledTaskService {

    @Autowired
    private ScheduledTaskDao scheduledTaskDao;

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    @Override
    public List<ScheduledTask> getAllScheduledTask() {
        return scheduledTaskDao.getAllScheduledTask();
    }

    @Override
    public void executeTask(Integer scheduledTaskId) {
        Optional<ScheduledTask> optionalScheduledTask = scheduledTaskDao.getScheduledTaskById(scheduledTaskId);
        if (optionalScheduledTask.isPresent()) {
            ScheduledTask scheduledTask = optionalScheduledTask.get();
            String cronExpression = scheduledTask.getCronExpression();
            JobDetail jobDetail = JobBuilder.newJob(ScheduledTaskJob.class)
                                            .withIdentity(scheduledTask.getJobName(), scheduledTask.getJobGroup())
                                            .storeDurably()
                                            .build();
            jobDetail.getJobDataMap().put("scheduledTaskId", scheduledTaskId);
            Trigger trigger = TriggerBuilder.newTrigger()
                                             .forJob(jobDetail)
                                             .withIdentity(scheduledTask.getTriggerName(), scheduledTask.getTriggerGroup())
                                             .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                                             .build();
            try {
                Scheduler scheduler = schedulerFactoryBean.getScheduler();
                scheduler.addJob(jobDetail, true, true);
                scheduler.scheduleJob(trigger);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }
}

ScheduledTaskServiceImpl 中使用了 ScheduledTaskDao 中定义的方法来获取数据库中的任务信息,然后通过 JobBuilder 和 TriggerBuilder 对任务和触发器进行构建,并且将任务和触发器关联,将任务存入调度中心并且执行。

另外,我们还需要定义一个 Job,用于执行定时任务。以下是该 Job 的具体实现:

@Service
public class ScheduledTaskJob implements Job {

    @Autowired
    private ScheduledTaskDao scheduledTaskDao;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        Integer scheduledTaskId = (Integer) dataMap.get("scheduledTaskId");
        Optional<ScheduledTask> optionalScheduledTask = scheduledTaskDao.getScheduledTaskById(scheduledTaskId);
        if (optionalScheduledTask.isPresent()) {
            ScheduledTask scheduledTask = optionalScheduledTask.get();
            // TODO 执行具体的任务逻辑
            System.out.println(new Date() + "执行定时任务:" + scheduledTask.getTaskName());
        }
    }
}

ScheduledTaskJob 中实现了 Quartz 的 Job 接口,并且通过 ScheduledTaskDao 从数据库中获取任务信息,然后执行具体的业务逻辑。该 Job 中的任务逻辑可以是任何我们想要执行的具体业务逻辑,比如发送邮件、统计数据、备份数据等等。

最后,我们需要定义一个存放定时任务信息的实体类 ScheduledTask:

public class ScheduledTask {

    private Integer scheduledTaskId;

    private String taskName;

    private String jobName;

    private String jobGroup;

    private String triggerName;

    private String triggerGroup;

    private String cronExpression;

    // 省略 getter 和 setter 方法
}

ScheduledTask 类中定义了任务的各项属性,包括任务 ID、任务名称、Job 名称、Job 组、Trigger 名称、Trigger 组以及任务的 Cron 表达式等。

示例讲解

接下来,我们来看两个示例,分别用于演示如何创建并执行定时任务。

首先,我们来创建一个每分钟执行一次的任务。

  1. 假设我们已经在数据库中创建好了一条定时任务信息:

scheduled_task_id:1

task_name:每分钟执行一次的任务

job_name:job1

job_group:group1

trigger_name:trigger1

trigger_group:group1

cron_expression:0 0/1 * * * ?

@Component
public class EveryMinuteJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("This is a job which will be executed every minute.");
    }
}

@Configuration
public class QuartzConfig {
    @Bean(name = "everyMinuteJobDetail")
    public JobDetail everyMinuteJobDetail() {
        return JobBuilder.newJob(EveryMinuteJob.class).withIdentity("job1", "group1").storeDurably().build();
    }

    @Bean(name = "everyMinuteJobTrigger")
    public Trigger everyMinuteJobTrigger() {
        return TriggerBuilder.newTrigger().forJob(everyMinuteJobDetail()).withIdentity("trigger1", "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?")).build();
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setJobDetails(everyMinuteJobDetail());
        factory.setTriggers(everyMinuteJobTrigger());
        return factory;
    }
}
  1. 然后,我们在 ScheduledTaskServiceImpl 中创建一个方法,并调用 executeTask 方法来执行该定时任务:
@Service
public class ScheduledTaskServiceImpl implements ScheduledTaskService {

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    @Override
    public List<ScheduledTask> getAllScheduledTask() {
        return scheduledTaskDao.getAllScheduledTask();
    }

    @Override
    public void executeTask(Integer scheduledTaskId) {
        Optional<ScheduledTask> optionalScheduledTask = scheduledTaskDao.getScheduledTaskById(scheduledTaskId);
        if (optionalScheduledTask.isPresent()) {
            ScheduledTask scheduledTask = optionalScheduledTask.get();
            String cronExpression = scheduledTask.getCronExpression();
            JobDetail jobDetail = JobBuilder.newJob(EveryMinuteJob.class)
                                            .withIdentity(scheduledTask.getJobName(), scheduledTask.getJobGroup())
                                            .storeDurably()
                                            .build();
            Trigger trigger = TriggerBuilder.newTrigger()
                                             .forJob(jobDetail)
                                             .withIdentity(scheduledTask.getTriggerName(), scheduledTask.getTriggerGroup())
                                             .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                                             .build();
            try {
                Scheduler scheduler = schedulerFactoryBean.getScheduler();
                scheduler.addJob(jobDetail, true, true);
                scheduler.scheduleJob(trigger);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 最后,我们可以在 controller 中调用 executeTask 方法来执行该定时任务:
@RestController
@RequestMapping("/scheduledTask")
public class ScheduledTaskController {

    @Autowired
    private ScheduledTaskService scheduledTaskService;

    @RequestMapping("/execute")
    public String executeScheduledTask() {
        scheduledTaskService.executeTask(1);
        return "execute success.";
    }
}

现在,我们来创建一个每天 10:15 执行一次的任务。

  1. 假设我们已经在数据库中创建好了一条定时任务信息:

scheduled_task_id:2

task_name:每天 10:15 执行一次的任务

job_name:job2

job_group:group2

trigger_name:trigger2

trigger_group:group2

cron_expression:0 15 10 ? * *

@Component
public class EveryDayJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("This is a job which will be executed every day at 10:15.");
    }
}

@Configuration
public class QuartzConfig {
    @Bean(name = "everyDayJobDetail")
    public JobDetail everyDayJobDetail() {
        return JobBuilder.newJob(EveryDayJob.class).withIdentity("job2", "group2").storeDurably().build();
    }

    @Bean(name = "everyDayJobTrigger")
    public Trigger everyDayJobTrigger() {
        return TriggerBuilder.newTrigger().forJob(everyDayJobDetail()).withIdentity("trigger2", "group2")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 15 10 ? * *")).build();
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setJobDetails(everyDayJobDetail());
        factory.setTriggers(everyDayJobTrigger());
        return factory;
    }
}
  1. 然后,我们在 ScheduledTaskServiceImpl 中创建一个方法,并调用 executeTask 方法来执行该定时任务:
@Service
public class ScheduledTaskServiceImpl implements ScheduledTaskService {

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    @Override
    public List<ScheduledTask> getAllScheduledTask() {
        return scheduledTaskDao.getAllScheduledTask();
    }

    @Override
    public void executeTask(Integer scheduledTaskId) {
        Optional<ScheduledTask> optionalScheduledTask = scheduledTaskDao.getScheduledTaskById(scheduledTaskId);
        if (optionalScheduledTask.isPresent()) {
            ScheduledTask scheduledTask = optionalScheduledTask.get();
            String cronExpression = scheduledTask.getCronExpression();
            JobDetail jobDetail = JobBuilder.newJob(EveryDayJob.class)
                                            .withIdentity(scheduledTask.getJobName(), scheduledTask.getJobGroup())
                                            .storeDurably()
                                            .build();
            Trigger trigger = TriggerBuilder.newTrigger()
                                             .forJob(jobDetail)
                                             .withIdentity(scheduledTask.getTriggerName(), scheduledTask.getTriggerGroup())
                                             .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                                             .build();
            try {
                Scheduler scheduler = schedulerFactoryBean.getScheduler();
                scheduler.addJob(jobDetail, true, true);
                scheduler.scheduleJob(trigger);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 最后,我们可以在 controller 中调用 executeTask 方法来执行该定时任务:
@RestController
@RequestMapping("/scheduledTask")
public class ScheduledTaskController {

    @Autowired
    private ScheduledTaskService scheduledTaskService;

    @RequestMapping("/execute")
    public String executeScheduledTask() {
        scheduledTaskService.executeTask(2);
        return "execute success.";
    }
}

至此,我们已经通过 SpringBoot 框架实现了动态创建并执行定时任务的功能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解SpringBoot 创建定时任务(配合数据库动态执行) - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • SpringBoot项目中的多数据源支持的方法

    为在Spring Boot项目中实现多数据源支持,有几种方法可供选择。以下是几种最常用的方法。 方法一:使用Spring Boot提供的自动配置 Spring Boot自动配置对于多个数据源配置非常方便。可以使用@ConfigurationProperties注释来定义不同的数据源。以下是实现多个数据源的示例: # application.yml sprin…

    Java 2023年5月20日
    00
  • SpringBoot2使用JTA组件实现基于JdbcTemplate多数据源事务管理(亲测好用)

    SpringBoot2使用JTA组件实现基于JdbcTemplate多数据源事务管理(亲测好用) 前置条件 在使用本教程前,请确保您已经具备以下要求: 对Java开发有一定的了解和基础 对JdbcTemplate、SpringBoot、JTA等技术有基本的了解 理解多数据源、事务管理等概念 背景 随着业务的发展,我们可能需要连接多个数据库来存储数据,这时候我…

    Java 2023年5月20日
    00
  • springAop实现权限管理数据校验操作日志的场景分析

    下面是关于“springAop实现权限管理数据校验操作日志的场景分析”的完整攻略,包含两个示例说明。 springAop实现权限管理数据校验操作日志的场景分析 Spring AOP(Aspect Oriented Programming)是一种面向切面编程的技术,它可以在不修改原有代码的情况下,对系统进行横向切割,实现诸如权限管理、数据校验、操作日志等功能。…

    Java 2023年5月17日
    00
  • nginx+tomcat实现负载均衡,使用redis session共享

    实现负载均衡可以利用反向代理服务器来实现,而Nginx就是一个出色的反向代理服务器,同时,通过Tomcat实现负载均衡的同时还需要使用Redis session共享来实现负载均衡下的session一致性。 下面就是实现“nginx+tomcat实现负载均衡,使用redis session共享”的完整攻略: 环境准备 安装Nginx、Tomcat和Redis;…

    Java 2023年5月19日
    00
  • 读取Java文件到byte数组的三种方法(总结)

    这里为您详细讲解“读取Java文件到byte数组的三种方法(总结)”的完整攻略。 什么是“读取Java文件到byte数组”? 将 Java 文件读取为 byte 数组可以用于在编程中进行很多操作,比如文件传输、加密等。在 Java 中,我们可以通过多种方式来实现这一目的,下面将介绍三种常用的方法。 方法一:使用FileInputStream和ByteArra…

    Java 2023年5月20日
    00
  • Java 如何快速实现一个连接池

    实现一个连接池是一个非常基础的场景,Java中已经有很多开源框架提供了连接池的实现,比如Druid、HikariCP、C3P0等。其中,HikariCP是目前性能最快的连接池,下面我们以HikariCP为例讲解如何快速实现一个连接池。 1. 添加Maven依赖 首先,在项目的Maven pom.xml文件中添加HikariCP的依赖: <depende…

    Java 2023年5月19日
    00
  • SpringMVC后端返回数据到前端代码示例

    SpringMVC后端返回数据到前端代码示例的完整攻略如下: 1. 定义Controller类 首先要定义一个Controller类,用于处理前端的请求,然后返回数据给前端。以下是示例代码: @RestController @RequestMapping("/api") public class UserController { @Aut…

    Java 2023年6月15日
    00
  • Spring JdbcTemplate执行数据库操作详解

    Spring JdbcTemplate执行数据库操作详解 什么是Spring JdbcTemplate? Spring JdbcTemplate是一个基于JDBC的模板框架,它简化了JDBC API的使用,提供了异常处理、资源管理以及线程安全等特性。JdbcTemplate可以连接任何数据库,仅通过一些简单的配置,就可以执行SQL查询和更新,以及管理事务。 …

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部