Giap Hiep

I'm Giap Hiep

I'm a web developer, a gymer. I enjoy share something i know that help people's work!
Giap Hiep

Job scheduling trong Spring Boot

Job scheduling là một công việc chúng ta thường hay gặp trong khi xây dựng các ứng dụng. Để thực hiện job scheduling trong Spring Boot, chúng ta có thể áp dụng một trong hai cách sau:

  1. Sử dụng annotation @Scheduled
  2. Sử dụng thư viện Quartz

...

1. Sử dụng annotation @Scheduled

1.1. Enable scheduling

Với cách này, trước tiên chúng ta cần phải enable scheduling trong Spring Boot bằng cách thêm annotation @EnableScheduling ở configuration class:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

1.2. Annotation @Scheduled

Annotatinon @Scheduled được khai báo bên trên method xử lý job.

Method này phải đảm bảo 2 yêu cầu sau:

  • Trả về void.
  • Không được ném ra các ngoại lệ.

Các tham số thường dùng của @Scheduled là:

long initialDelay

Khoảng thời gian được tính từ thời điểm startup của ứng dụng Spring Boot cho đến thời điểm bắt đầu của lần thực thi đầu tiên của method xử lý job. Đơn vị: millisecond.

long fixedDelay

Chúng ta có thể dùng kết hợp initialDelay với fixedDelay. Lúc này, thời điểm của các lần thực thi method xử lý job sẽ là:

  • Lần thực thi thứ 1: sau initialDelay
  • Lần thực thi thứ 2: sau khi lần thực thi thứ 1 chấm dứt + fixedDelay
  • Lần thực thi thứ 3: sau khi lần thực thi thứ 2 chấm dứt + fixedDelay
  • Lần thực thi thứ 4: sau khi lần thực thi thứ 3 chấm dứt + fixedDelay
  • ...

long fixedRate

Chúng ta có thể dùng kết hợp initialDelay với fixedRate. Lúc này, thời điểm của các lần thực thi method xử lý job sẽ là:

  • Lần thực thi thứ 1: sau initialDelay
  • Lần thực thi thứ 2: sau initialDelay + fixedRate
  • Lần thực thi thứ 3: sau initialDelay + 2 * fixedRate
  • Lần thực thi thứ 4: sau initialDelay + 3 * fixedRate
  • ...

String cron

Biểu thức crontab: method xử lý job sẽ được thực thi tại đúng thời điểm thỏa mãn biểu thức crontab.

Chú ý: Phải đảm bảo một và chỉ một trong 3 tham số initialDelay, fixedDelaycron xuất hiện khi khai báo @Scheduled.

1.3. Ví dụ

Mình sẽ viết một job cứ 5 giây in thời gian hiện tại 1 lần.

PrintNowService.java

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

@Service
public class PrintNowService {

    @Scheduled(fixedDelay = 5000)
    public void printNow() {
        System.out.println(LocalDateTime.now());
    }
}

Chạy ứng dụng Spring Boot và chúng ta sẽ thấy kết quả như sau:

2020-01-15T10:22:52.437
2020-01-15T10:22:57.437
2020-01-15T10:23:02.444
...

2. Sử dụng thư viện Quartz

2.1. Spring Boot Quartz

Quartz sử dụng các đối tượng Trigger, JobJobDetail để thực hiện job scheduling.

Để tích hợp thư viện Quartz trong Spring Boot, chúng ta sẽ khai báo Quartz starter trong pom.xml:

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

2.2. Ví dụ

Mình sẽ viết một job cứ 5 giây in 1 số ngẫu nhiên.

PrintRandomService.java: lớp xử lý logic của job.

import org.springframework.stereotype.Service;

import java.util.concurrent.ThreadLocalRandom;

@Service
public class PrintRandomService {

    public void printRandom() {
        System.out.println(ThreadLocalRandom.current().nextInt());
    }
}

PrintRandomJob.java: bean đại diện cho job và phải kế thừa org.springframework.scheduling.quartz.QuartzJobBean.

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class PrintRandomJob extends QuartzJobBean {

    @Autowired
    private PrintRandomService printRandomService;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        printRandomService.printRandom();
    }
}

JobConfiguration.java: lớp cấu hình JobDetailTrigger của job.

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JobConfiguration {

    @Bean
    public JobDetail printRandomJobDetail() {
        return JobBuilder
                .newJob(PrintRandomJob.class)
                .withIdentity(JobKey.jobKey("printRandom"))
                .storeDurably()
                .build();
    }

    @Bean
    public Trigger printRandomJobTrigger() {
        return TriggerBuilder
                .newTrigger()
                .forJob(printRandomJobDetail())
                .withIdentity(TriggerKey.triggerKey("printRandom"))
                .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))
                .build();
    }
}

Chạy ứng dụng Spring Boot và chúng ta sẽ thấy kết quả như sau:

-1727615121
878308058
-803885137
...