SpringBoot официально поддерживает фреймворк планирования задач, а еще очень приятно быть легковесным!

Spring Boot Java
SpringBoot официально поддерживает фреймворк планирования задач, а еще очень приятно быть легковесным!

Адрес фактического центра электронной коммерции SpringBoot (40k+star):GitHub.com/macro-positive/…

Резюме

Ранее мы говорили о распределенной среде планирования задач PowerJob, которая может планировать задачи визуально. Но иногда нам просто нужна легкая функция планирования задач, и для PowerJob немного тяжело построить центр планирования.В этот раз нам пригодится Quartz, инфраструктура планирования задач, официально поддерживаемая SpringBoot! В этой статье в основном рассказывается об использовании Quartz в SpringBoot, что дает вам больше возможностей для реализации планирования задач!

О кварце

Quartz — это мощная платформа планирования задач с открытым исходным кодом, которую можно интегрировать практически в любое приложение Java (от небольшого автономного приложения до большого распределенного приложения). Quartz можно использовать для создания простых или сложных расписаний задач для выполнения десятков тысяч задач. Задачи определяются как стандартизированные компоненты Java, и задачи, написанные на Java, могут выполняться.

основная концепция

В Quartz есть несколько основных концепций, и их понимание очень полезно для использования Quartz!

  • Планировщик: планировщик задач в Quartz, который можно использовать для планирования, приостановки и удаления задач с помощью Trigger и JobDetail.
  • Триггер: триггер в Quartz, вы можете указать время выполнения задачи с помощью выражения CRON, и выполнение задачи будет автоматически запущено, когда время истечет.
  • JobDetail (сведения о задаче): сведения о задачах, которые должны быть выполнены в Quartz, включая уникальный идентификатор задачи и конкретную задачу, которую необходимо выполнить.Данные могут быть переданы в задачу через JobDataMap.
  • Работа (задача): конкретная задача в Quartz, включая конкретный метод выполнения задачи.

CRON-выражение

Выражение Cron представляет собой строку, включающую 6~7 элементов времени, которые можно использовать для указания времени выполнения задач в Quartz.

Синтаксис CRON

Seconds Minutes Hours DayofMonth Month DayofWeek

Описание каждого элемента времени в формате CRON

элемент времени символы, которые могут появиться допустимый диапазон значений
Seconds , - * / 0-59
Minutes , - * / 0-59
Hours , - * / 0-23
DayofMonth , - * / ? L W 0-31
Month , - * / 1-12
DayofWeek , - * / ? L # 1-7 или вс-сб

Описание специальных символов в формате CRON

персонаж эффект Пример
, Список значений перечисления Используйте 5, 10 в поле «Минуты», что означает, что он срабатывает один раз в 5 минут и 10 минут каждый.
- Указывает диапазон срабатывания Используйте 5-10 в поле «Минуты», чтобы запускать каждую минуту от 5 до 10 минут.
* соответствует любому значению Используйте * в поле «Минуты», чтобы указать, что он будет запускаться каждую минуту.
/ Время начала начинает срабатывать, и срабатывает каждое фиксированное время Используйте 5/10 в поле «Минуты», что означает, что он срабатывает каждые 5 минут и каждые 10 минут.
? В DayofMonth и DayofWeek для сопоставления произвольных значений Используйте ? в поле DayofMonth, чтобы указать, что он запускается один раз в день.
# В DayofMonth определите день недели 1#3 означает третье воскресенье
L значит последний Используйте 5L в DayofWeek для срабатывания в последний четверг
W Указывает допустимые рабочие дни (с понедельника по пятницу) Используйте 5W в DayofMonth, если 5-е число — суббота, оно сработает один раз 4-го числа ближайшего рабочего дня.

Онлайн-генератор выражений CRON

На самом деле нет необходимости запоминать выражение CRON, когда вам нужно его использовать, вы можете напрямую использовать онлайн-генератор.Адрес:cron.qqe2.com/

Интеграция использования SpringBoot

Далее давайте поговорим о том, как использовать Quartz в SpringBoot для планирования задач.В системе электронной коммерции часто возникает необходимость регулярно отправлять электронные письма или сообщения на сайте.Давайте рассмотрим это как сценарий для достижения этой цели!

  • Существует два способа хранения информации о задаче в Quartz: использование памяти или использование базы данных для ее хранения.Здесь мы используем метод хранения базы данных.Во-первых, нам нужно создать новую таблицу, связанную с Quartz.Скрипт построения таблицы хранится в папке проекта.resourcesкаталог с именемtables_mysql.sql, после успешного создания в БД остается еще 11 таблиц;

  • следующий вpom.xmlПросто добавьте соответствующие зависимости Quartz, SpringBoot официально предоставил нам соответствующий Starter;
<!--SpringBoot集成QuartZ-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
  • существуетapplication.ymlДобавьте конфигурацию, связанную с Quartz, в конфигурацию, просто посмотрите комментарии к инструкциям по настройке, в основном дляscheduler,jobStoreиthreadPoolнастроить;
spring:
  quartz:
    job-store-type: jdbc # quartz任务存储类型:jdbc或memory
    wait-for-jobs-to-complete-on-shutdown: true # 关闭时等待任务完成
    overwrite-existing-jobs: true # 可以覆盖已有的任务
    properties: # quartz原生配置
      org:
        quartz:
          scheduler:
            instanceName: scheduler # 调度器实例名称
            instanceId: AUTO # 调度器实例ID自动生成
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX # 调度信息存储处理类
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # 使用完全兼容JDBC的驱动
            tablePrefix: QRTZ_ # quartz相关表前缀
            useProperties: false # 是否将JobDataMap中的属性转为字符串存储
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool # 指定线程池实现类,对调度器提供固定大小的线程池
            threadCount: 10 # 设置并发线程数量
            threadPriority: 5 # 指定线程优先级
  • Создайте бизнес-интерфейс планирования задач и определите три метода, а именно планирование задач с помощью выражений CRON, планирование задач в указанное время и отмену запланированных задач;
/**
 * Quartz定时任务操作类
 * Created by macro on 2020/9/27.
 */
public interface ScheduleService {
    /**
     * 通过CRON表达式调度任务
     */
    String scheduleJob(Class<? extends Job> jobBeanClass, String cron, String data);

    /**
     * 调度指定时间的任务
     */
    String scheduleFixTimeJob(Class<? extends Job> jobBeanClass, Date startTime, String data);

    /**
     * 取消定时任务
     */
    Boolean cancelScheduleJob(String jobName);
}
  • Создайте класс бизнес-реализации планирования задач с помощьюScheduler,CronTrigger,JobDetailметоды, связанные с реализацией API;
/**
 * Quartz定时任务操作实现类
 * Created by macro on 2020/9/27.
 */
@Slf4j
@Service
public class ScheduleServiceImpl implements ScheduleService {
    @Autowired
    private Scheduler scheduler;
    private String defaultGroup = "default_group";

    @Override
    public String scheduleJob(Class<? extends Job> jobBeanClass, String cron, String data) {
        // 创建需要执行的任务
        String jobName = UUID.fastUUID().toString();
        JobDetail jobDetail = JobBuilder.newJob(jobBeanClass)
                .withIdentity(jobName, defaultGroup)
                .usingJobData("data", data)
                .build();
        //创建触发器,指定任务执行时间
        CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName, defaultGroup)
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                .build();
        //使用调度器进行任务调度
        try {
            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.info("创建定时任务失败!");
        }
        return jobName;
    }

    @Override
    public String scheduleFixTimeJob(Class<? extends Job> jobBeanClass, Date startTime, String data) {
        //日期转CRON表达式
        String startCron = String.format("%d %d %d %d %d ? %d",
                DateUtil.second(startTime),
                DateUtil.minute(startTime),
                DateUtil.hour(startTime, true),
                DateUtil.dayOfMonth(startTime),
                DateUtil.month(startTime) + 1,
                DateUtil.year(startTime));
        return scheduleJob(jobBeanClass, startCron, data);
    }

    @Override
    public Boolean cancelScheduleJob(String jobName) {
        boolean success = false;
        try {
            // 暂停触发器
            scheduler.pauseTrigger(new TriggerKey(jobName, defaultGroup));
            // 移除触发器中的任务
            scheduler.unscheduleJob(new TriggerKey(jobName, defaultGroup));
            // 删除任务
            scheduler.deleteJob(new JobKey(jobName, defaultGroup));
            success = true;
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return success;
    }
}
  • Определить задачи, которые необходимо выполнить, наследоватьQuartzJobBeanкласс, реализоватьexecuteInternalМетода достаточно, здесь определены три задачи: регулярная отправка электронных писем, регулярная отправка сообщений на сайте и выполнение задач выражения CRON;
/**
 * 发送邮件定时任务执行器
 * Created by macro on 2020/9/27.
 */
@Slf4j
@Component
public class SendEmailJob extends QuartzJobBean {
    @Autowired
    private ScheduleService scheduleService;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        Trigger trigger = jobExecutionContext.getTrigger();
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String data = jobDataMap.getString("data");
        log.info("定时发送邮件操作:{}",data);
        //完成后删除触发器和任务
        scheduleService.cancelScheduleJob(trigger.getKey().getName());
    }
}
/**
 * 发送站内信定时任务执行器
 * Created by macro on 2020/9/27.
 */
@Slf4j
@Component
public class SendMessageJob extends QuartzJobBean {
    @Autowired
    private ScheduleService scheduleService;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        Trigger trigger = jobExecutionContext.getTrigger();
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String data = jobDataMap.getString("data");
        log.info("定时发送站内信操作:{}",data);
        //完成后删除触发器和任务
        scheduleService.cancelScheduleJob(trigger.getKey().getName());
    }
}
/**
 * 使用CRON表达式的任务执行器
 * Created by macro on 2020/9/29.
 */
@Slf4j
@Component
public class CronProcessJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String data = jobDataMap.getString("data");
        log.info("CRON表达式任务执行:{}",data);
    }
}
  • Наконец, создайте интерфейс, связанный с планированием задач, и вызовите бизнес-класс планирования задач.
/**
 * 定时任务调度相关接口
 * Created by macro on 2020/9/29.
 */
@Api(tags = "ScheduleController", description = "定时任务调度相关接口")
@RestController
@RequestMapping("/schedule")
public class ScheduleController {
    @Autowired
    private ScheduleService scheduleService;

    @ApiOperation("定时发送邮件")
    @PostMapping("/sendEmail")
    public CommonResult sendEmail(@RequestParam String startTime,@RequestParam String data) {
        Date date = DateUtil.parse(startTime, DatePattern.NORM_DATETIME_FORMAT);
        String jobName = scheduleService.scheduleFixTimeJob(SendEmailJob.class, date, data);
        return CommonResult.success(jobName);
    }

    @ApiOperation("定时发送站内信")
    @PostMapping("/sendMessage")
    public CommonResult sendMessage(@RequestParam String startTime,@RequestParam String data) {
        Date date = DateUtil.parse(startTime, DatePattern.NORM_DATETIME_FORMAT);
        String jobName = scheduleService.scheduleFixTimeJob(SendMessageJob.class, date, data);
        return CommonResult.success(jobName);
    }

    @ApiOperation("通过CRON表达式调度任务")
    @PostMapping("/scheduleJob")
    public CommonResult scheduleJob(@RequestParam String cron, @RequestParam String data) {
        String jobName = scheduleService.scheduleJob(CronProcessJob.class, cron, data);
        return CommonResult.success(jobName);
    }

    @ApiOperation("取消定时任务")
    @PostMapping("/cancelScheduleJob")
    public CommonResult cancelScheduleJob(@RequestParam String jobName) {
        Boolean success = scheduleService.cancelScheduleJob(jobName);
        return CommonResult.success(success);
    }
}

запустить тест

  • Вызовите тест интерфейса, чтобы регулярно отправлять электронную почту;

  • Достигнув точки, обнаруживается, что консоль напечатала информацию о выполнении задачи;
2020-09-30 11:23:00.035  INFO 10160 --- [eduler_Worker-1] com.macro.mall.tiny.job.SendEmailJob     : 定时发送邮件操作:发送邮件内容
  • Используйте выражение CRON для запуска запланированной задачи, начиная с 0 и выполняя ее каждые 10 с;

  • Консоль выводит информацию о выполнении задачи каждые 10 секунд;
2020-09-30 11:26:30.024  INFO 10160 --- [eduler_Worker-2] com.macro.mall.tiny.job.CronProcessJob   : CRON表达式任务执行:CRON消息内容
2020-09-30 11:26:40.025  INFO 10160 --- [eduler_Worker-3] com.macro.mall.tiny.job.CronProcessJob   : CRON表达式任务执行:CRON消息内容
2020-09-30 11:26:50.017  INFO 10160 --- [eduler_Worker-4] com.macro.mall.tiny.job.CronProcessJob   : CRON表达式任务执行:CRON消息内容
2020-09-30 11:27:00.023  INFO 10160 --- [eduler_Worker-5] com.macro.mall.tiny.job.CronProcessJob   : CRON表达式任务执行:CRON消息内容
2020-09-30 11:27:10.019  INFO 10160 --- [eduler_Worker-6] com.macro.mall.tiny.job.CronProcessJob   : CRON表达式任务执行:CRON消息内容
  • Можем вернуться, запустив заданиеjobName, вызовите интерфейс отмены запланированной задачи, чтобы отменить задачу, и запланированная задача не будет выполняться после успешного вызова.

использованная литература

Официальная документация:woohoo.quartz-scheduler.org/document ATI…

Адрес исходного кода проекта

GitHub.com/macro-positive/…

Эта статьяGitHubGitHub.com/macro-positive/…Он был записан, приветствую всех на Star!