Spring Boot 2.X (12): запланированные задачи

Spring Boot

Введение

Запланированные задачи являются распространенным требованием в серверной разработке.Основные сценарии приложений включают в себя регулярные отчеты о данных, регулярные уведомления о сообщениях, асинхронную фоновую обработку бизнес-логики, анализ и обработку журналов, очистку данных от мусора и регулярные обновления кэша.

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. Тест

Журнал печати выглядит следующим образом:

образец кода

github

Облако кода

Если не указано иное, авторские права на эту статью принадлежатутренний туманВсе, пожалуйста, указывайте источник при перепечатке.

Оригинальное название: Spring Boot 2.X (12): запланированные задачи.

Оригинальный адрес: https://www.zwqh.top/article/info/21

Если статья была вам полезна, отсканируйте код и подпишитесь на мой официальный аккаунт, статья постоянно обновляется...