首先來看看spring的定時任務的類結構
Application是springboot的啟動類。
TimedTask是所有定時任務的接口
ResourceMakingTask是定時任務執行的線程池、定時任務的初始化管理的類。
NormalVideoMakingTask是一個具體的定時任務。
首先來看看 TimedTask 定時任務的接口類
import java.util.concurrent.ScheduledExecutorService;/*** 定時任務的接口*/public interface TimedTask extends Runnable { /** * 將定時任務提交到ScheduledThreadPool線程池中運行 * @param makingPool */ void addSelfToThreadPoolToRun(ScheduledExecutorService makingPool);}
繼承Runable接口,定時任務需要放到線程池中執行,需要實現一個Runnable接口
定義一個addSelfToThreadPoolToRun方法,定時任務如何添加到線程池,這個方法需要傳入一個線程池,就是執行這個定時任務的線程池,定時任務的延時、間隔時間等都是由這個方法來實現。
再來看看定時任務接口的一個實現類 NormalVideoMakingTask
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/*** 普通視頻製作的定時任務*/@Component//將bean交給spring管理public class NormalVideoMakingTask implements TimedTask { private static Logger log = LoggerFactory.getLogger(NormalVideoMakingTask.class); /** * 運行任務,添加定時邏輯 */ @Override public void addSelfToThreadPoolToRun(ScheduledExecutorService makingPool) { //任務1s後執行,執行完畢後休眠1s再重複執行 makingPool.scheduleWithFixedDelay(this,1,1, TimeUnit.SECONDS); } /** * 定時任務 的 任務業務邏輯。 */ @Override public void run() { log.debug("普通視頻製作定時任務:{}","開始"); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { log.error(e.getLocalizedMessage()); } log.debug("普通視頻製作定時任務:{}","完成"); }}
定時任務運行線程池的創建和任務的添加 ResourceMakingTask 類
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 資源製作任務啟動管理類 * 實現ApplicationContextAware接口是為了能得到spring的上下文 * 以便通過spring的上下文來得到所有的定時任務的bean批量啟動
*/
@Component
public class ResourceMakingTask implements ApplicationContextAware {
private static Logger log = LoggerFactory.getLogger(ResourceMakingTask.class);
/**
* spring上下文
*/
ApplicationContext applicationContext;
/**
* spingboot環境變量
*/
@Resource
Environment env;//springboot 的環境變量
/**
* 執行製作定時任務的線程池
*/
ScheduledExecutorService makingPool; //這個註解在spring創建完成此類時執行此方法
@PostConstruct
public void runTask(){
//初始化線程池
initMakingPool();
/*
使用一個新的線程來等待spring初始化結束
不阻塞spring的初始化過程
*/
makingPool.execute(new Runnable(){
@Override
public void run() {
try {
//延遲10s或更長,給於spring充分的時間,
//創建初始化所有的定時任務bean
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
log.error(e.getLocalizedMessage());
}
//添加定時任務
addTimedTask();
}
});
}
/**
* 添加定時任務
*/
private void addTimedTask() {
//通過spring上下文獲取所有實現TimedTask接口的bean
Map<String, TimedTask> tasks = applicationContext.getBeansOfType(TimedTask.class);
Set<String> keys = tasks.keySet();
for(String timedTaskName : keys){
//將定時任務添加到線程池運行
tasks.get(timedTaskName).addSelfToThreadPoolToRun(makingPool);
log.debug("添加定時任務:{}",timedTaskName);
}
}
/**
* 初始化線程池
*/
private void initMakingPool() {
if (makingPool != null){
makingPool.shutdown();
}
String poolSizeStr = env.getProperty("makingTask.poolSize");
int poolSize = 1;
try {
poolSize = Integer.parseInt(poolSizeStr);
}catch (Exception e){
e.printStackTrace();
log.error(e.getLocalizedMessage());
}
makingPool = Executors.newScheduledThreadPool(poolSize);
}
/**
* 注入spring上下文
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}