参考文章:https://blog.csdn.net/sinianliushui/article/details/78841713
参考文章: https://blog.csdn.net/hao7030187/article/details/79077464
参考文章:https://www.cnblogs.com/domi22/p/9418433.html
springboot的SchedulerTask相对Quartz来说,简单方便,可试用于小型的job处理。
因没法持久化因此不支持分布式部署,和动态数据源配置。
如果要
一、简易配置
1. 开启定时任务,在启动类添加以下注解
@EnableScheduling
2. 创建并发配置,并发线程
@Component public class SchedulerConfig implements SchedulingConfigurer { /** * 设置定时任务 * @param scheduledTaskRegistrar */ @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(5)); } }
3. 创建scheduler,以下是没5秒触发一次,cron表达式有cron在线生成器可以用
@Component @Slf4j public class SchedulerTask { @Scheduled(cron="0/5 * * * * ? ") public void testTask(){ DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); log.debug(Thread.currentThread() + " " + sdf.format(new Date())); }
@Scheduled(cron="0/5 * * * * ? ")
public void test2Task(){
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
log.debug(Thread.currentThread() + " " + sdf.format(new Date()));
}
}
二、分开配置
如下例子,如果只有一个Bean,名字为taskScheduler,或者方法名为taskScheduler则会作为自动的Scheduler。使用 @Scheduled即对应的是此TaskScheduler。
参见文章: https://blog.csdn.net/sinianliushui/article/details/78841713
/** * description: * 定时任务 * @Autor:DennyZhao * @Date:2019/2/15 * @Version: 1.0.0 */ @Component @EnableScheduling public class SchedulerConfig { /** task相关的属性文件 **/ @Autowired private TaskProperties taskProperties; /** * 设备组织用Job * @return */ @Bean("DeviceJob") public TaskScheduler initDeviceOrgTask(){ ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); //线程池大小 scheduler.setPoolSize(taskProperties.getDeviceThreadCount()); //线程名字前缀 scheduler.setThreadNamePrefix("taskThread-deviceTask: "); scheduler.initialize(); Trigger trigger = new CronTrigger(taskProperties.getDeviceOrgCron()); scheduler.schedule(new DeviceOrgTask(), trigger); return scheduler; } /** * Jpush用Job * @return */ @Bean("JpushJob") public TaskScheduler initJpushTask(){ ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); //线程池大小 scheduler.setPoolSize(taskProperties.getJpushThreadCount()); //线程名字前缀 scheduler.setThreadNamePrefix("taskThread-jpushTask: "); scheduler.initialize(); Trigger trigger = new CronTrigger(taskProperties.getJpushReportCron()); scheduler.schedule(new JpushReportTask(), trigger); return scheduler; } }
TaskPropertis
/** * description: * JPUSH执行任务相关参数 * * @Autor:DennyZhao * @Date:2019/2/15 * @Version: 1.0.0 */ @Component @PropertySource("classpath:task-config.properties") @ConfigurationProperties(prefix="task") @Data public class TaskProperties { /** 极光推送appKey **/ private String jpushAppKey; /** 极光推送secretKey **/ private String jpushSecretKey; /** 设备JOB的线程数 **/ private int deviceThreadCount; /** 设备组织Cron **/ private String deviceOrgCron; /** Jpush的JOB线程数 **/ private int jpushThreadCount; /** Jpush的推送报告Cron **/ private String jpushReportCron; }
创建类实现Runable接口即可使用。
@Component @Slf4j public class DeviceOrgTask implements Runnable { @Override public void run() { DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); log.debug(Thread.currentThread() + " " + sdf.format(new Date())); } }
问题:
1. 从以上的一简易配置中(如果不添加SchedulerConfig)也可以运行,发现如果在方法中添加Thread.sleep(),会影响下面方法的运行和下次的运行时间。
因为默认的 ConcurrentTaskScheduler 计划执行器采用Executors.newSingleThreadScheduledExecutor() 实现单线程的执行器。
因此要使用异步: 采用异步的方式执行调度任务,配置 Spring 的 @EnableAsync,在执行定时任务的方法上标注 @Async配置任务执行。注意线程池大小要依据单个任务时间和任务间隔。
2. 分布式重复执行
1.使用 redis分布式锁setnx命令 来控制是否已经存在有任务在执行。
2.使用spring的shedLock,创建一个数据表,先更新者执行,非更新者不执行。
参见:https://segmentfault.com/a/1190000011975027
3. 主程序挂掉后,job停止,数据丢失
使用redis记录执行时间。
异常:
[ERROR] 2019-03-21 14:00:38,757 >>> org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler.handleError(TaskUtils.java:96)
[massage] Unexpected error occurred in scheduled task.
java.lang.IllegalStateException: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@8f84321 has been closed already
使用applicationContext未获取到bean异常。
因EnabledTask会使得任务在执行完后closeContext导致,在配置文件添加:
spring.cloud.task.closecontext_enable=false
高版本用 spring.cloud.task.close_context_enabled=false
参考文章: https://stackoverflow.com/questions/48933575/spring-cloud-task-scheduling-context-closed