本文使用Spring框架自带的Scheduled注解来实现Java定时任务,只说明不停止服务自定义时间执行任务。
配置
在Spring框架的主启动类上加上@EnableScheduling注解,表示开启定时任务,具体的执行任务在其他类。
执行
表达式
在执行类的方法上增加@Scheduled(cron = "* * * * * ?")注解,
cron的参数示例如下:
| 参数 |
值 |
允许的特殊字符 |
| 秒 |
0-59 |
, - * / |
| 分 |
0-59 |
, - * / |
| 小时 |
0-23 |
, - * / |
| 日 |
1-31 |
, - * ? / L W C |
| 月 |
1-12 或者 JAN-DEC |
, - * / |
| 星期 |
1-7 或者 SUN-SAT |
, - * ? / L C # |
| 年(可选) |
留空, 1970-2099 |
, - * / |
0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 0 12 ? * WED 表示每个星期三中午12点
“0 0 12 * * ?” 每天中午12点触发
“0 15 10 ? * *” 每天上午10:15触发
“0 15 10 * * ?” 每天上午10:15触发
“0 15 10 * * ? *” 每天上午10:15触发
“0 15 10 * * ? 2005” 2005年的每天上午10:15触发
“0 * 14 * * ?” 在每天下午2点到下午2:59期间的每1分钟触发
“0 0/5 14 * * ?” 在每天下午2点到下午2:55期间的每5分钟触发
“0 0/5 14,18 * * ?” 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
“0 0-5 14 * * ?” 在每天下午2点到下午2:05期间的每1分钟触发
“0 10,44 14 ? 3 WED” 每年三月的星期三的下午2:10和2:44触发
“0 15 10 ? * MON-FRI” 周一至周五的上午10:15触发
“0 15 10 15 * ?” 每月15日上午10:15触发
“0 15 10 L * ?” 每月最后一日的上午10:15触发
“0 15 10 ? * 6L” 每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6#3” 每月的第三个星期五上午10:15触发
有些子表达式能包含一些范围或列表
例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT”
“*”字符代表所有可能的值
因此,“”在子表达式(月)里表示每个月的含义,“”在子表达式(天(星期))表示星期的每一天
动态修改时间
资源文件配置变量
cron使用自定义变量,在SpringCloud的配置中心修改即可不重启服务使用修改后的变量
保存到数据库
将时间表达式保存到数据库,从程序中读取,就可以随时修改任务时间
表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `spring_scheduled_cron`; CREATE TABLE `spring_scheduled_cron` ( `cron_id` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键id', `cron_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '定时任务完整类名', `cron_expression` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'cron表达式', `task_explain` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '任务描述', `status` tinyint(0) NOT NULL DEFAULT 1 COMMENT '状态,1:正常;2:停用', PRIMARY KEY (`cron_id`) USING BTREE, UNIQUE INDEX `cron_key`(`cron_key`) USING BTREE, UNIQUE INDEX `cron_key_unique_idx`(`cron_key`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '定时任务表' ROW_FORMAT = Dynamic;
INSERT INTO `spring_scheduled_cron` VALUES ('1', 'com.example.springcloud0614.controller.DynamicPrintTask', '*/5 * * * * ?', '定时任务描述', 1); INSERT INTO `spring_scheduled_cron` VALUES ('2', 'com.example.springcloud0614.controller.DynamicPrintTask1', '*/5 * * * * ?', '定时任务描述1', 1); INSERT INTO `spring_scheduled_cron` VALUES ('3', 'com.example.springcloud0614.controller.DynamicPrintTask2', '*/5 * * * * ?', '定时任务描述2', 1);
SET FOREIGN_KEY_CHECKS = 1;
|
Spring工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package com.example.springcloud0614.config;
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest; import java.util.Locale;
@Component public class SpringUtils implements ApplicationContextAware { private static ApplicationContext applicationContext;
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }
public static <T> T getBean(Class<T> tClass){ return applicationContext.getBean(tClass); }
public static <T> T getBean(String name, Class<T> type) { return applicationContext.getBean(name, type); }
public static HttpServletRequest getCurrentReq() { ServletRequestAttributes requestAttrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (requestAttrs == null) { return null; } return requestAttrs.getRequest(); }
public static String getMessage(String code, Object... args) { LocaleResolver localeResolver = getBean(LocaleResolver.class); Locale locale = localeResolver.resolveLocale(getCurrentReq()); return applicationContext.getMessage(code, args, locale); }
}
|
定时任务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| package com.example.springcloud0614.config;
import com.example.springcloud0614.entity.ScheduledCron; import com.example.springcloud0614.service.ScheduledCronService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.scheduling.config.Task; import org.springframework.scheduling.support.CronTrigger; import org.springframework.util.Assert;
import java.util.concurrent.Executor; import java.util.concurrent.Executors;
@Configuration @Slf4j public class ScheduledConfig implements SchedulingConfigurer {
@Autowired private ApplicationContext context; @Autowired private ScheduledCronService cronService;
@Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { for (ScheduledCron scheduledCron : cronService.findAll()) { log.info("表达式:{}", scheduledCron); Class<?> clazz; Object task; try { clazz = Class.forName(scheduledCron.getCronKey()); task = context.getBean(clazz); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("spring_scheduled_cron表数据" + scheduledCron.getCronKey() + "有误", e); } catch (BeansException e) { throw new IllegalArgumentException(scheduledCron.getCronKey() + "未纳入到spring管理", e); } Assert.isAssignable(ScheduledOfTask.class, task.getClass(), "定时任务类必须实现ScheduledOfTask接口"); taskRegistrar.addTriggerTask(((Runnable) task), triggerContext -> { String cronExpression = cronService.findByCronId(scheduledCron.getCronId()).getCronExpression(); return new CronTrigger(cronExpression).nextExecutionTime(triggerContext); } ); } }
@Bean public Executor taskExecutor() { return Executors.newScheduledThreadPool(10); } }
|
启用和禁用功能
如果不需要可以不实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.example.springcloud0614.config;
import com.example.springcloud0614.entity.ScheduledCron; import com.example.springcloud0614.service.ScheduledCronService;
public interface ScheduledOfTask extends Runnable {
void execute();
@Override default void run() { ScheduledCronService cronService = SpringUtils.getBean(ScheduledCronService.class); ScheduledCron scheduledCron = cronService.findByCronKey(this.getClass().getName()); if (scheduledCron.getStatus() == 0) { return; } execute(); } }
|
定时任务
其余方法一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.example.springcloud0614.controller;
import com.example.springcloud0614.config.ScheduledOfTask; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller;
@Slf4j @Controller public class DynamicPrintTask implements ScheduledOfTask { private int i;
@Override public void execute() { log.info("DynamicPrintTask execute times:{}", ++i); } }
|