需求说明
- 每天定时0点执行清洗任务。
- 项目启动时执行清洗任务。
- 不能干扰项目启动。
- 默认从2023年1月1日开始执行清洗任务。
注意
实现思路
- 使用Scheduled注解完成定时功能。
- 使用PostConstruct注解设定项目启动时执行。
- 使用ThreadPoolExecutor执行多线程任务,不影响项目主线程。
- 使用ApplicationContextAware接口,通过上下文获取bean对象。
代码
package com.xxx.scheduling;
import com.xxx.DateUtil;
import com.xxx.ValidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
public interface CleanTaskAble{
Logger logger = LoggerFactory.getLogger(CleanTaskAble.class);
default void runTask() {
String taskInfor = "cleanTask " + this.getClass().getSimpleName();
Date lastDate = getLastDate();
if (ValidUtil.isEmpty(lastDate)) {
lastDate = DateUtil.parse("2023-01-01 00:00:00", DateUtil.yyyyMMddHHmmssPattern);
}
clean(lastDate);
logger.debug(taskInfor + " end");
}
Date getLastDate();
void clean(Date startDate);
}
- SchedulingWebConfig调度环境类。
package com.xxx.scheduling;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
@Configuration
@EnableScheduling
@Slf4j
public class SchedulingWebConfig implements ApplicationContextAware {
private final List<CleanTaskAble> taskList = new ArrayList<>(8);
private final ThreadPoolExecutor exec;
public SchedulingWebConfig() {
/*
* corePoolSize为0,没有及时性要求,设置为0减少内存消耗。
* maximumPoolSize为4,不需要占用太多的资源;
* keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;
* LinkedBlockingQueue,可变长度任务队列,最大值为100。
*/
this.exec = new ThreadPoolExecutor(0, 4,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(100));
}
//每天0点0分0秒定时执行
@Scheduled(cron = "0 0 0 * * ?")
public void cleanTasks() {
log.info("daily tasks start");
clean();
log.info("daily tasks end");
}
//项目启动时执行
@PostConstruct
public void cleanWhenInit() {
log.info("init tasks start");
clean();
log.info("init tasks end");
}
//使用线程池,不影响项目主体
private void clean() {
log.info("exec infor:" + exec);
for (CleanTaskAble task : taskList) {
exec.submit(() -> {
try {
log.info(task.getClass().getSimpleName() + " clean task begin!");
task.runTask();
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
taskList.addAll(applicationContext.getBeansOfType(CleanTaskAble.class).values());
}
}