Введение
Запланированные задачи являются распространенным требованием в серверной разработке.Основные сценарии приложений включают в себя регулярные отчеты о данных, регулярные уведомления о сообщениях, асинхронную фоновую обработку бизнес-логики, анализ и обработку журналов, очистку данных от мусора и регулярные обновления кэша.
Spring Boot интегрирует полный набор инструментов для задач синхронизации, что позволяет нам сосредоточиться на выполнении логики, а остальная часть основной работы по планированию будет выполняться автоматически.
Общая реализация
Метод реализации | описывать |
---|---|
java.util.Timer | Timer предоставляет задачу java.util.TimerTask для поддержки планирования задач. Этот метод может выполняться только с указанной частотой, а не в указанное время. Поскольку функция слишком одиночная, она используется меньше. |
Quartz | Quartz — это мощный планировщик, поддерживающий запуск в указанное время или с заданной частотой. Недостатком является то, что он относительно громоздкий в использовании. |
Модуль Schedule, входящий в состав Spring Framework. | Можно рассматривать как легкий кварц |
статическая запланированная задача
@Component
@EnableScheduling
public class StaticScheduleJob {
/**
* 上次开始执行时间点后5秒再次执行
*/
@Scheduled(fixedRate = 5000)
public void job3() {
System.out.println("执行任务job3:"+DateUtil.formatDateTime(new Date()));
}
/**
* 上次执行完毕时间点后3秒再次执行
*/
@Scheduled(fixedDelay = 3000)
public void job2() {
System.out.println("执行任务job2:"+DateUtil.formatDateTime(new Date()));
}
/**
* 每隔10秒执行一次(按照 corn 表达式规则执行)
*/
@Scheduled(cron = "0/10 * * * * ?")
public void job1() {
System.out.println("执行任务job1:"+DateUtil.formatDateTime(new Date()));
}
}
Аннотация @EnableScheduling включает планирование времени
Описание параметра @Scheduled:
- @Scheduled(fixedRate = 5000): выполнить снова через 5 секунд после последней точки времени выполнения
- @Scheduled(fixedDelay = 3000): выполнить снова через 3 секунды после последней точки времени выполнения
- @Scheduled(cron = "0/10 * * * * ?"): Выполнять каждые 10 секунд (в соответствии с правилами выражения кукурузы)
Cron-выражения
1. Формат выражения Cron
{секунды} {минуты} {часы} {дни} {месяцы} {недели} {годы (необязательно)}
2. Диапазон значений поля выражения Cron и описание
поле | Диапазоны | разрешенные специальные символы |
---|---|---|
Секунды | 0 ~ 59 | , - * / |
Минуты | 0 ~ 59 | , - * / |
Часы | 0 ~ 23 | , - * / |
День месяца | Можно использовать любое значение от 1 до 31, но обратите внимание на особый месяц | , - * ? / L W C |
Месяц | Может быть представлено цифрами от 0 до 11 или строкой «ЯНВ, ФЕВ, МАР, АПРЕЛЬ, МАЙ, ИЮН, ИЮЛ, АВГУСТ, СЕН, ОКТ, НОЯБРЬ, ДЕК». | , - * / |
День недели (еженедельно) | Может быть представлен числом от 1 до 7 (1 = воскресенье) или строкой «ВС, ПН, ВТ, СР, ЧТ, ПТ, СБ». | , - * ? / L C # |
Год | Диапазон значений (1970-2099), допускаются нулевые значения | , - * / |
3. Значение специальных символов в выражениях Cron
Специальные символы | иллюстрировать |
---|---|
* | Указывает, что все значения поля могут быть сопоставлены |
? | В основном используется для дня и недели, может соответствовать любому значению поля, но не фактическому. Когда одному из двух подвыражений присваивается значение, во избежание конфликтов значение другого подвыражения должно быть установлено равным ? |
/ | Выражается интервалом. Например, 0 0/10 * * * ?, где 0/10 означает запуск с 0 минут и выполнение каждые 10 минут. |
- | Указывает диапазон. Например, 0 0-5 14 * * ? означает выполнять каждую 1 минуту с 14:00 до 14:05 каждый день |
, | Представляет собой перечисление нескольких значений, которые «соединены» между собой. Например, 0 10,30 14 * 3 ? означает, что выполняется один раз каждый вторник в 14:10 или 14:30. |
L | Указывает последний день месяца или недели. Например, 0 0 0 L * ? * означает выполнение в последний день каждого месяца |
W | Указывает последний рабочий день. Вроде 0 0 0 15 Вт * ? * Указывает на исполнение в ближайший рабочий день 15 числа каждого месяца |
# | Используется для указания определенного количества недель, "#" перед представляет неделю, а "#" после него представляет неделю месяца. Например, "2#1" означает второе воскресенье месяца. |
4. Инструмент онлайн-генерации Cron
woohoo.be JSON.com/другие инструменты/…
Динамические запланированные задачи
1. Реализуйте интерфейс SchedulingConfigurer.
@Configuration
public class CustomScheduleConfig implements SchedulingConfigurer {
@Autowired
private CronTriggerDao cronTriggerDao;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 上次开始执行时间点后5秒再执行
taskRegistrar.addFixedRateTask(() -> System.out.println("CustomScheduleConfig执行任务job1=>"
+ DateUtil.formatDateTime(new Date()) + ",线程:" + Thread.currentThread().getName()), 5000);
// 上次执行完毕时间点后3秒再执行
taskRegistrar.addFixedDelayTask(() -> System.out.println("CustomScheduleConfig执行任务job2=>"
+ DateUtil.formatDateTime(new Date()) + ",线程:" + Thread.currentThread().getName()), 3000);
// 添加一个配合数据库动态执行的定时任务
TriggerTask triggerTask = new TriggerTask(
// 任务内容.拉姆达表达式
() -> {
// 1)添加任务 Runnable
System.out.println("CustomScheduleConfig执行动态任务job3=>" + DateUtil.formatDateTime(new Date()) + ",线程:"
+ Thread.currentThread().getName());
// 2)设置执行周期
}, triggerContext -> {
// 3)从数据库获取执行周期
String cron = cronTriggerDao.getCronTriggerById(1L);
if (cron != null) {
// 4)返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
} else {
return null;
}
});
taskRegistrar.addTriggerTask(triggerTask);
}
}
2. Инициализировать данные в базе данных
Здесь для тестирования просто инициализируйте две строки данных:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_cron_trigger
-- ----------------------------
DROP TABLE IF EXISTS `t_cron_trigger`;
CREATE TABLE `t_cron_trigger` (
`id` int(8) NOT NULL AUTO_INCREMENT COMMENT '任务id',
`cron` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT 'cron表达式',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`is_deleted` int(1) DEFAULT '0' COMMENT '作废状态 0-否 1-是',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of t_cron_trigger
-- ----------------------------
BEGIN;
INSERT INTO `t_cron_trigger` VALUES (1, '0/10 * * * * ?', '2019-10-30 13:40:14', NULL, 0);
INSERT INTO `t_cron_trigger` VALUES (2, '0/7 * * * * ?', '2019-10-30 13:40:34', NULL, 0);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
3. Считайте значение выражения cron из базы данных.
Класс сущности CronTrigger
public class CronTrigger implements Serializable{
/**
*
*/
private static final long serialVersionUID = 880141459783509786L;
private Long id;//任务id
private String cron;//cron表达式
private String createTime;//创建时间
private String updateTime;//更新时间
private boolean isDeleted=false;//删除状态
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCron() {
return cron;
}
public void setCron(String cron) {
this.cron = cron;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public String getUpdateTime() {
return updateTime;
}
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
public boolean isDeleted() {
return isDeleted;
}
public void setDeleted(boolean isDeleted) {
this.isDeleted = isDeleted;
}
}
CronTriggerDao
public interface CronTriggerDao {
/**
* 根据id获取cron表达式
* @param id
* @return
*/
String getCronTriggerById(Long id);
}
CronTriggerMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.4//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.zwqh.springboot.dao.CronTriggerDao">
<resultMap type="cn.zwqh.springboot.model.CronTrigger" id="cronTrigger">
<id property="id" column="id"/>
<result property="cron" column="cron"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="isDeleted" column="is_deleted"/>
</resultMap>
<!-- 根据id获取cron表达式 -->
<select id="getCronTriggerById" resultType="String">
select cron from t_cron_trigger where is_deleted=0 and id=#{id}
</select>
</mapper>
4. Тест
Не забудьте добавить @EnableScheduling в класс запуска перед запуском.
Журнал печати выглядит следующим образом:
Многопоточные задачи синхронизации
Из приведенного выше журнала мы видим, что выполнение задачи является однопоточным. Если мы хотим реализовать многопоточные задачи выполнения, мы можем добавить пул потоков в метод configureTasks интерфейса SchedulingConfigurer.
1.CustomScheduleConfig
@Configuration
public class CustomScheduleConfig implements SchedulingConfigurer {
@Autowired
private CronTriggerDao cronTriggerDao;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//设定一个长度为10的定时任务线程池
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
// 上次开始执行时间点后5秒再执行
taskRegistrar.addFixedRateTask(() -> System.out.println("CustomScheduleConfig执行任务job1=>"
+ DateUtil.formatDateTime(new Date()) + ",线程:" + Thread.currentThread().getName()), 5000);
// 上次执行完毕时间点后3秒再执行
taskRegistrar.addFixedDelayTask(() -> System.out.println("CustomScheduleConfig执行任务job2=>"
+ DateUtil.formatDateTime(new Date()) + ",线程:" + Thread.currentThread().getName()), 3000);
// 添加第一个配合数据库动态执行的定时任务
TriggerTask triggerTask = new TriggerTask(
// 任务内容.拉姆达表达式
() -> {
// 1)添加任务 Runnable
System.out.println("CustomScheduleConfig执行动态任务job3=>" + DateUtil.formatDateTime(new Date()) + ",线程:"
+ Thread.currentThread().getName());
// 2)设置执行周期
}, triggerContext -> {
// 3)从数据库获取执行周期
String cron = cronTriggerDao.getCronTriggerById(1L);
if (cron != null) {
// 4)返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
} else {
return null;
}
});
taskRegistrar.addTriggerTask(triggerTask);
// 添加第二个配合数据库动态执行的定时任务
TriggerTask triggerTask2 = new TriggerTask(
// 任务内容.拉姆达表达式
() -> {
// 1)添加任务 Runnable
System.out.println("CustomScheduleConfig执行动态任务job4=>" + DateUtil.formatDateTime(new Date()) + ",线程:"
+ Thread.currentThread().getName());
// 2)设置执行周期
}, triggerContext -> {
// 3)从数据库获取执行周期
String cron = cronTriggerDao.getCronTriggerById(2L);
if (cron != null) {
// 4)返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
} else {
return null;
}
});
taskRegistrar.addTriggerTask(triggerTask2);
}
}
2. Тест
Журнал печати выглядит следующим образом:
образец кода
Если не указано иное, авторские права на эту статью принадлежатутренний туманВсе, пожалуйста, указывайте источник при перепечатке.
Оригинальное название: Spring Boot 2.X (12): запланированные задачи.
Оригинальный адрес: https://www.zwqh.top/article/info/21
Если статья была вам полезна, отсканируйте код и подпишитесь на мой официальный аккаунт, статья постоянно обновляется...