SpringBoot 定时任务的实现
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot 定时任务的实现相关的知识,希望对你有一定的参考价值。
介绍两种实现方式;配置实现和读取数据库定时任务配置实现。
配置实现比较简单。直接撸代码:
package com;
import java.util.Properties;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplicationbr/>@ImportResource("classpath:/config.xml")
@EnableAutoConfiguration
@ComponentScan
@EnableTransactionManagement(proxyTargetClass = true) br/>@MapperScan({"com.*.model.*.mapper","com.*.task"})
@EnableScheduling
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
@Bean
public DatabaseIdProvider getDatabaseIdProvider() {
}
}br/>注:在启动类上加注解
@EnableScheduling
@MapperScan 扫描定时任务配置文件的位置。
其他地方无需关注。
定时任务配置类:
package com.*.task;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class RunTaskConfig {
private static final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
//初始延迟1秒,每隔2秒
@Scheduled(fixedRateString = "2000",initialDelay = 1000)
public void testFixedRate(){
System.out.println("fixedRateString,当前时间:" +format.format(new Date()));
}
//每次执行完延迟2秒
@Scheduled(fixedDelayString= "2000")
public void testFixedDelay(){
System.out.println("fixedDelayString,当前时间:" +format.format(new Date()));
}
//每隔3秒执行一次
@Scheduled(cron="0/3 * * * * ?")
public void testCron(){
System.out.println("cron,当前时间:" +format.format(new Date()));
}
}
配置完成,项目启动后配置的定时任务会自动执行。
Springboot 定时任务 的数据库实现方式:
数据表实体
id , 执行类, 执行方法, 是否生效, 时间表达式;
SpringBoot 定时任务实现原理:启动Spring 会扫描@Scheduled 注解,读取注解配置信息。
获取定时任务,解析,注册成可执行的定时任务。
数据库活动定时任务实现具体代码如下
package com.tansun.task;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ScheduledExecutorService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.NamedBeanHolder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.tansun.model.system.dao.RunTaskDao;
import com.tansun.model.system.dao.RunTaskDaoImpl;
import com.tansun.model.system.dao.RunTaskSqlBulider;
import com.tansun.model.system.entity.RunTask;
import com.tansun.web.framework.util.BeanUtil;
/***
- 定时任务启动类,从数据库读取定时任务配置。监控定时任务运行。
-
@author kangx
*/
@Component("BeanDefineConfigue")
public class EventListen implements ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware{public static final String DEFAULT_TASK_SCHEDULER_BEAN_NAME = "taskScheduler";
protected final Log logger = LogFactory.getLog(getClass());
// 任务调度对象引用
private Object scheduler;private String beanName;
private BeanFactory beanFactory;
// 配置环境上下文信息
private ApplicationContext applicationContext;
// 任务调度注册中心,监控定时任务,设置定时任务启动触发器。
private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();// 定时任务执行体
private final Map<Object, Set<ScheduledTask>> scheduledTasks =
new IdentityHashMap<Object, Set<ScheduledTask>>(16);public Object getScheduler() {
return scheduler;
}public void setScheduler(Object scheduler) {
this.scheduler = scheduler;
}
//EmbeddedValueResolver embeddedValueResolver=new EmbeddedValueResolver(null);br/>@Override
public void onApplicationEvent(ContextRefreshedEvent event) {try { RunTaskDao runTaskDao = BeanUtil.getBean(RunTaskDaoImpl.class); RunTaskSqlBulider runTaskSqlBulider = new RunTaskSqlBulider(); //查找启动状态的定时任务 runTaskSqlBulider.andIsWorkEqualTo("1"); int count = runTaskDao.countBySqlBulider(runTaskSqlBulider); List<RunTask> list = new ArrayList<>(); if(count>0){ list = runTaskDao.selectListBySqlBulider(runTaskSqlBulider); } for(RunTask runtask:list){ //定时任务对象解析,装配及注册 processScheduled(runtask); } // 定时任务注册,启动定时任务 finishRegistration(); } catch (Exception e) { e.printStackTrace(); }
}
/**
- 定时任务注册
*/
private void finishRegistration() {
if (this.scheduler != null) {
this.registrar.setScheduler(this.scheduler);
}
if (this.beanFactory instanceof ListableBeanFactory) {
Map<String, SchedulingConfigurer> configurers =
((ListableBeanFactory) this.beanFactory).getBeansOfType(SchedulingConfigurer.class);
for (SchedulingConfigurer configurer : configurers.values()) {
configurer.configureTasks(this.registrar);
}
}
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
try {
this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, false));
}
catch (NoUniqueBeanDefinitionException ex) {
try {
this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, true));
}
catch (NoSuchBeanDefinitionException ex2) {
// 日志记录
ex2.printStackTrace();
}
}
catch (NoSuchBeanDefinitionException ex) {
// Search for ScheduledExecutorService bean next...
try {
this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, false));
}
catch (NoUniqueBeanDefinitionException ex2) {
try {
this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, true));
}
catch (NoSuchBeanDefinitionException ex3) {
// 日志记录
ex3.printStackTrace();
}
}
catch (NoSuchBeanDefinitionException ex2) {
// 异常日志
ex2.printStackTrace();
}
}
}
this.registrar.afterPropertiesSet();
}
private <T> T resolveSchedulerBean(Class<T> schedulerType, boolean byName) {
if (byName) {
T scheduler = this.beanFactory.getBean(DEFAULT_TASK_SCHEDULER_BEAN_NAME, schedulerType);
if (this.beanFactory instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(
DEFAULT_TASK_SCHEDULER_BEAN_NAME, this.beanName);
}
return scheduler;
}
else if (this.beanFactory instanceof AutowireCapableBeanFactory) {
NamedBeanHolder<T> holder = ((AutowireCapableBeanFactory) this.beanFactory).resolveNamedBean(schedulerType);
if (this.beanFactory instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(
holder.getBeanName(), this.beanName);
}
return holder.getBeanInstance();
}
else {
return this.beanFactory.getBean(schedulerType);
}
}
/**
- 定时任务装配
- @throws ClassNotFoundException
- @throws SecurityException
-
@throws NoSuchMethodException
*/
protected void processScheduled(RunTask runTask) throws Exception{
try {
Class clazz = Class.forName(runTask.getExecuteClass());
Object bean = clazz.newInstance();
Method method = clazz.getMethod(runTask.getExecuteMethod(), null);
Method invocableMethod = AopUtils.selectInvocableMethod(method, clazz);
Runnable runnable = new ScheduledMethodRunnable(bean, invocableMethod);
boolean processedSchedule = false;Set<ScheduledTask> tasks = new LinkedHashSet<ScheduledTask>(4); String cron = runTask.getTimeExpression(); if (StringUtils.hasText(cron)) { processedSchedule = true; String zone = ""; TimeZone timeZone; if (StringUtils.hasText(zone)) { timeZone = StringUtils.parseTimeZoneString(zone); } else { timeZone = TimeZone.getDefault(); } tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone)))); } // Finally register the scheduled tasks synchronized (this.scheduledTasks) { Set<ScheduledTask> registeredTasks = this.scheduledTasks.get(bean); if (registeredTasks == null) { registeredTasks = new LinkedHashSet<ScheduledTask>(4); this.scheduledTasks.put(bean, registeredTasks); } registeredTasks.addAll(tasks); }
}
catch (IllegalArgumentException ex) {
// 日志
ex.printStackTrace();
}
}
/** - 获取环境上下文信息br/>*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
if (this.beanFactory == null) {
this.beanFactory = applicationContext;
}
}
}
- 定时任务注册
以上是关于SpringBoot 定时任务的实现的主要内容,如果未能解决你的问题,请参考以下文章
springboot项目使用SchedulingConfigurer实现多个定时任务
SpringBoot使用SchedulingConfigurer实现多个定时任务多机器部署问题