整体设计思路:
数据库 任务配置TASK表:REPEAT 字段表示是否需要重复执行,当不重复时CRON为具体时间点,只会执行一次
Task实体类和Mapper.xml 根据数据库字段自行创建。
废话不多说,直接上代码。
package com.yfjz.config;
import com.yfjz.model.AppData;
import com.yfjz.model.Task;
import com.yfjz.service.AppDataService;
import com.yfjz.service.BaseService;
import com.yfjz.utils.Constant;
import com.yfjz.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.scheduling.support.CronTrigger;
import java.util.*;
/**
* @Author: zxh
* @Description: 扫描数据库配置的定时任务,根据cron执行;支持定时任务动态添加修改
* @Date: 2018/11/19 10:44
* @Version: 1.0
*/
@Configuration
@EnableScheduling
public class ScheduleConfig extends BaseService implements SchedulingConfigurer {
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
private static List<Task> tasks;
private static boolean initialized = false;
private static ContextLifecycleScheduledTaskRegistrar taskRegistrar;
private final AppDataService appDataService;
@Autowired
public ScheduleConfig(AppDataService appDataService) {
this.appDataService = appDataService;
}
/**
* @Description: 每隔一小时 扫描一次任务配置,重构定时任务时,把线程池中的任务关闭
* @Param: [] 0 0/10 * * * ? 0 0 0/1 * * ?
* @return: void
* @Date: 2018/11/19 13:38
*/
@Scheduled(cron = "0 0 0/1 * * ?")
public void bTask() {
try {
if (initialized) {
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown( false );
threadPoolTaskScheduler.shutdown();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
tasks = taskMapper.selectAllTask( new HashMap<>() );
configureTasks( tasks );
}
}
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
if (tasks == null) {
bTask();
} else {
configureTasks( tasks );
}
}
/**
* @Description: 并行任务調用,多线程处理
* @Param: [tasks]
* @return: void
* @Date: 2018/11/19 13:22
*/
private void configureTasks(List<Task> tasks) {
threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize( 100 );//线程池大小
threadPoolTaskScheduler.setThreadNamePrefix( "configureTasks-" );
threadPoolTaskScheduler.setAwaitTerminationSeconds( 60 );//线程等待時間
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown( true );//等待所有任務執行完在銷毀
threadPoolTaskScheduler.initialize();
initialized = true;
if (taskRegistrar != null)
taskRegistrar.destroy();
taskRegistrar = new ContextLifecycleScheduledTaskRegistrar();
taskRegistrar.setTaskScheduler( threadPoolTaskScheduler );
for (Task task : tasks) {
Runnable runnable = new Runnable() {
@Override
public void run() {
List<AppData> list = appDataMapper.selectAllAppData( task.getAppId() );
if (!StringUtils.isEmpty( task.getCron() ) && task.getRepeat().equals( "1" )) {
savaAppData( list, task );
} else if (task.getRepeat().equals( "0" )) {
if (isLong( task.getCron() )) {
long num = System.currentTimeMillis() - Long.valueOf( task.getCron() );
Timer timer = new Timer();
timer.schedule( new TimerTask() {
@Override
public void run() {
savaAppData( list, task );
}
}, num );
}
}
}
};
Trigger trigger = new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
CronTrigger cronTrigger = new CronTrigger( task.getCron() );
return cronTrigger.nextExecutionTime( triggerContext );
}
};
TriggerTask triggerTask = new TriggerTask( runnable, trigger );
taskRegistrar.setTriggerTasksList( Collections.singletonList( triggerTask ) );
taskRegistrar.afterSingletonsInstantiated();
}
}
private void savaAppData(List<AppData> list, Task task) {
if (list.size() > 0) {
String[] name = list.get( 0 ).getName().split( "_" );
if (name.length > 0) {
AppData appData = new AppData();
appData.setId( getMaxSequences( Constant.DBTP_APP_DATA_SEQ ) );
appData.setName( getAppNo( name[0], name[1] ) );
appData.setAppId( task.getAppId() );
appData.setStatus( "0" );
appData.setUserId( task.getApp().getUserId() );
appDataMapper.insertSelective( appData );
try {
//根据应用执行表ID查询对应的最新的一条服务作业表,看状态是否为2 已执行
if (!list.get( 0 ).getStatus().equals( "2" )) {
appDataService.runJob( appData.getId(), task.getApp().getProcessId(), task.getApp().getUserId(), task.getApp().getEntityId() );
}
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
AppData appData = new AppData();
appData.setId( getMaxSequences( Constant.DBTP_APP_DATA_SEQ ) );
appData.setName( task.getApp().getName() + "_00001" );
appData.setAppId( task.getAppId() );
appData.setStatus( "0" );
appData.setUserId( task.getApp().getUserId() );
appDataMapper.insertSelective( appData );
try {
appDataService.runJob( appData.getId(), task.getApp().getProcessId(), task.getApp().getUserId(), task.getApp().getEntityId() );
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static boolean isLong(String str) {
if (null == str || str.length() == 0) {
return false;
}
for (int i = str.length(); --i >= 0; ) {
int c = str.charAt( i );
if (c < 48 || c > 57) {
return false;
}
}
return true;
}
public static String getAppNo(String appName, String appNo) {
String newAppNo = "_1";
if (StringUtils.isEmpty( appNo )) {
appNo = "0";
}
if (!StringUtils.isEmpty( appName )) {
int newNo = Integer.parseInt( appNo ) + 1;
newAppNo = String.format( appName + "_" + "%05d", newNo );
} else {
newAppNo = appName + newAppNo;
}
return newAppNo;
}
}
2、启动SpringBoot Application 即可看到相关打印信息。
3、不足之处望指点