SpringBoot整合Schedule详解和优化实战



前言

Spring Schedule是Spring框架提供的一种简单的定时任务解决方案。它是基于Java的@Scheduled注解,可以让我们在不影响主线程的情况下,定时、周期性地执行任务。

为什么选择Spring Schedule

选择Spring Schedule作为定时任务的原因主要有以下几点:

  • 简单易用:Spring Schedule的使用非常简单,只需要在方法上添加@Scheduled注解,就可以将该方法变为定时任务。
  • 集成方便:如果你的项目已经是Spring框架,那么使用Spring Schedule不需要额外引入其他依赖,只需要简单的配置即可。
  • 支持CRON表达式:Spring Schedule支持CRON表达式,这使得我们可以非常灵活地配置定时任务的执行时间。
  • 支持异步执行:Spring Schedule支持异步执行任务,这意味着定时任务的执行不会阻塞主线程。

Cron表达式

Cron 表达式是一个字符串,由多个时间字段组成,用空格分隔。一个标准的 Cron 表达式有 6 个或 7 个字段,分别表示秒、分钟、小时、日期、月份、星期以及(可选的)年份。

  • 秒(0-59)
  • 分(0-59)
  • 时(0-23)
  • 日(1-31)
  • 月(1-12 或 JAN-DEC)
  • 周(1-7 或 SUN-SAT)
  • 年(可选,留空表示任意年份)

除了上述基本的取值范围外,Cron 表达式还支持一些特殊字符,如:

*:代表所有可能的值。例如,使用 * 表示每分钟、每小时或每月等。
/:用于指定一个增量。例如,0/15 表示从 0 分钟开始,每隔 15 分钟执行一次。
-:用于指定一个范围。例如,10-20 表示从 10 到 20。
,:用于列举多个取值。例如,MON,WED,FRI 表示星期一、星期三和星期五。
?:用于天或星期字段,表示无需指定具体值。

简单示例

这里我做了一个简单的示例:这里写了两个定时任务,同一个时间往数据库里面插入数据,每个任务插入1000条数据。

Application.class

@EnableScheduling
@SpringBootApplication
@MapperScan("org.example.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

这里记得要有@EnableScheduling注解,才能使用定时任务。

ScheduledService.class

package org.example.service;

import org.example.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class ScheduledService {

    @Autowired
    UserService userService;

    @Scheduled(cron = "0 08 10 * * ?")
    public void scheduledMethod(){
        System.out.println("第一个定时任务开始:"+ LocalDateTime.now());
        List<User> list = new ArrayList<User>();
        for(int i = 0;i<1000;i++){
            User user = new User();
            user.setId((long)i);
            user.setName("keaizp");
            user.setAge(25);
            list.add(user);
        }
        for (User user : list) {
            userService.insert(user);
        }
        System.out.println("第一个定时任务结束:"+ LocalDateTime.now());

    }


    @Scheduled(cron = "0 08 10 * * ?")
    public void Method2(){
        System.out.println("第二个定时任务开始:"+ LocalDateTime.now());
        List<User> list = new ArrayList<User>();
        for(int i = 1000;i<2000;i++){
            User user = new User();
            user.setId((long)i);
            user.setName("keaizp");
            user.setAge(25);
            list.add(user);
        }
        for (User user : list) {
            userService.insert(user);
        }
        System.out.println("第二个定时任务结束:"+ LocalDateTime.now());

    }
}

测试结果


可以看到定时任务会出现积压现象,虽然两个定时任务是设置同一时间的,但是第二个定时任务先执行,等第二个定时任务执行完成,第一个定时任务才开始执行。两个定时任务一共用时3分48秒。

优化方案

可以考虑使用异步执行的方式,使得任务的执行不会阻塞任务调度的进程。Spring Schedule默认是单线程执行任务的,如果有多个任务需要并行执行,那么可能会出现任务执行的延迟。这种情况下,可以考虑使用Spring Schedule的并行任务执行功能,通过配置TaskScheduler来实现。

package org.example.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

@Configuration
public class SchedulerConfig implements SchedulingConfigurer {

    private final int POOL_SIZE = 10;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();

        threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
        threadPoolTaskScheduler.setThreadNamePrefix("my-scheduled-task-pool-");
        threadPoolTaskScheduler.initialize();

        scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
    }
}

在这里插入图片描述
运行结果可以看到两个任务是并行执行的,两个任务完成一共用时1分54秒,效率大大得到提升!


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是整合步骤: 1. 在 pom.xml 中添加依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.21</version> </dependency> ``` 2. 在 application.yml 或 application.properties 文件中配置数据源和 Quartz: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/db_name?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver quartz: job-store-type: jdbc jdbc: initialize-schema: never # 默认值为 always,表示每次启动都会重新初始化表结构,这里设为 never,只在第一次启动时初始化 ``` 3. 创建一个 Quartz 配置类,用于配置 Quartz 的属性: ```java @Configuration public class QuartzConfig { @Autowired private DataSource dataSource; @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setDataSource(dataSource); schedulerFactoryBean.setQuartzProperties(quartzProperties()); schedulerFactoryBean.setSchedulerName("MyScheduler"); schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext"); schedulerFactoryBean.setAutoStartup(true); schedulerFactoryBean.setStartupDelay(5); return schedulerFactoryBean; } @Bean public Properties quartzProperties() { Properties properties = new Properties(); properties.setProperty("org.quartz.scheduler.instanceName", "MyScheduler"); properties.setProperty("org.quartz.scheduler.instanceId", "AUTO"); properties.setProperty("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); properties.setProperty("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"); properties.setProperty("org.quartz.jobStore.useProperties", "false"); properties.setProperty("org.quartz.jobStore.dataSource", "myDS"); properties.setProperty("org.quartz.jobStore.tablePrefix", "QRTZ_"); properties.setProperty("org.quartz.jobStore.isClustered", "true"); properties.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); properties.setProperty("org.quartz.threadPool.threadCount", "10"); properties.setProperty("org.quartz.dataSource.myDS.driver", "com.mysql.jdbc.Driver"); properties.setProperty("org.quartz.dataSource.myDS.URL", "jdbc:mysql://localhost:3306/db_name?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai"); properties.setProperty("org.quartz.dataSource.myDS.user", "root"); properties.setProperty("org.quartz.dataSource.myDS.password", "123456"); properties.setProperty("org.quartz.dataSource.myDS.maxConnections", "10"); return properties; } } ``` 4. 创建一个 Job 类,用于定义具体的任务: ```java public class MyJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { // 任务执行逻辑 } } ``` 5. 创建一个 Trigger 类,用于定义任务执行的时间规则: ```java public class MyTrigger { public static Trigger getTrigger() { SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(10) // 每 10 秒执行一次 .repeatForever(); return TriggerBuilder.newTrigger() .withIdentity("MyTrigger", "MyTriggerGroup") .withSchedule(scheduleBuilder) .startAt(new Date()) // 从当前时间开始执行 .build(); } } ``` 6. 在启动类中添加注解 @EnableScheduling,用于开启定时任务: ```java @SpringBootApplication @EnableScheduling public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 7. 在需要调度任务的地方,注入 Scheduler 对象,然后调用其 scheduleJob 方法即可: ```java @Autowired private Scheduler scheduler; public void scheduleJob() throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(MyJob.class) .withIdentity("MyJob", "MyJobGroup") .build(); Trigger trigger = MyTrigger.getTrigger(); scheduler.scheduleJob(jobDetail, trigger); } ``` 以上就是 Spring Boot 整合 Quartz 和 Druid 的步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值