springboot 动态修改定时任务
1、静态定时
1)启动类加上注解@EnableScheduling
@EnableAsync @EnableScheduling @SpringBootApplication @MapperScan("com.example.demo.mapper") @ComponentScan("com.example") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Autowired private Environment env; //destroy-method="close"的作用是当数据库连接不使用的时候,就把该连接重新放到数据池中,方便下次使用调用. //@Bean(destroyMethod = "close") public DataSource dataSource() { // } //为了打包springboot项目 protected SpringApplicationBuilder configure( SpringApplicationBuilder builder) { return builder.sources(this.getClass()); } }
2) 定时类加上@Component、定时方法添加@Scheduled(cron = "")即可 这里有一个在线生成cron的网站
@Component public class ScheduledTask { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); @Scheduled(cron = "0 30 * * * ?") @Async("asyncServiceExecutor") public void AutoGetAllData(){ // } }
这里默认的定时任务是单线程的,如果有多个任务同时触发,只能一个一个执行,如果想实现多线程,可以自行建立线程池工具类,再通过@Async()引用即可
线程池工具类
@Configuration @EnableAsync public class ExecutorConfig { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Bean public Executor asyncServiceExecutor(){ logger.info("start asyncServiceExecutor"); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //配置核心线程数 executor.setCorePoolSize(5); //配置最大线程数 executor.setMaxPoolSize(5); //配置队列大小 executor.setQueueCapacity(99999); //配置线程池中的线程的名称前缀 executor.setThreadNamePrefix("async-service-"); // rejection-policy:当pool已经达到max size的时候,如何处理新任务 // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //执行初始化 executor.initialize(); return executor; } }
2、动态定时
动态定时是通过继承SchedulingConfigurer,重写configureTasks方法实现的。
实现过程:
1、前台修改定时任务,更新数据库
2、定时器根据ID或者名称查询数据库中该方法的cron,注意修改之后不会立即实现,需等当前任务完成之后,下一次执行。这里有更详细的博客
@Component public class MyDynamicTask implements SchedulingConfigurer { @Autowired private TaskService taskService; private static Logger log = LoggerFactory.getLogger(MyDynamicTask.class); private String cron = "0/10 * * * * ? "; @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar){ if(getTrigger("InsertCaiYanShiJian")!=null){ scheduledTaskRegistrar.addTriggerTask(InsertCaiYanShiJian(), getTrigger("InsertCaiYanShiJian")); } if(getTrigger("AutoGetAllData")!=null){ scheduledTaskRegistrar.addTriggerTask(AutoGetAllData(), getTrigger("AutoGetAllData")); } } //定时任务1 private Runnable InsertCaiYanShiJian(){ return new Runnable() {
//注入Dao @Autowired private OrigDLDao origDLDao; @Autowired private OrigRtvDao origRtvDao; @Override public void run() { log.info("InsertCaiYanShiJian 每33秒执行一次,时间为:" + new Date(System.currentTimeMillis()));
//注入失败,通过工具类注入 if(origDLDao==null){ this.origDLDao = SpringBeanFactoryUtils.getBean(OrigDLDao.class); } if(origRtvDao==null){ this.origRtvDao = SpringBeanFactoryUtils.getBean(OrigRtvDao.class); } //具体逻辑 } }; } //定时任务2 private Runnable AutoGetAllData(){ return new Runnable(){ @Autowired private UtilDao utilDao; @Autowired private Client client; @Override public void run() { // 业务逻辑 log.info("AutoGetAllData 每十秒执行一次,时间为:" + new Date(System.currentTimeMillis())); if(utilDao==null){ this.utilDao = SpringBeanFactoryUtils.getBean(UtilDao.class); } if(client==null){ this.client = SpringBeanFactoryUtils.getBean(Client.class); } //具体逻辑 } }; }
private Trigger getTrigger(String taskName){ return new Trigger(){ @Override public Date nextExecutionTime(TriggerContext triggerContext) { // 触发器 if(getCron(taskName)==""){ return null; }else { CronTrigger trigger = new CronTrigger(getCron(taskName)); return trigger.nextExecutionTime(triggerContext); } } }; }
//通过任务名称获取Task,Task是一个对象,有任务ID,任务名称,任务描述,cron等 public String getCron(String taskName) { Task task = this.taskService.getTaskByName(taskName); if(task==null){ return ""; }else { return task.getTaskCron(); } } }
SpringBeanFactoryUtils工具类
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringBeanFactoryUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; /** * 获取静态变量中的ApplicationContext. */ public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) { //System.out.println(name); String[] str = applicationContext.getBeanDefinitionNames(); for (String string : str) { System.out.println("..." + string); } return (T) applicationContext.getBean(name); } /** * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型. */ public static <T> T getBean(Class<T> requiredType) { return applicationContext.getBean(requiredType); } /** * 实现ApplicationContextAware接口, 注入Context到静态变量中. */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }