问题场景
需求:每隔2小时抓取集群固定文件夹下的数据包进行分析产生报告。
实现方式
TimerTask使用单线程执行方式,当定时器遇到异常下次便不会执行,但可以用线程池调度弥补。
1、spring+ScheduledExecutorService+TimeTask
2、使用quartz-1.8.5.jar
解决步骤
a 编写任务类
b 编写监听类
c 用ScheduledExecutorService调用任务
a 编写任务类
package com.xxx.awk.listener;
import com.xxx.awk.service.*;
import lombok.extern.slf4j.Slf4j;
/**
*
* @author: youxingyang
* @date: 2018/8/30 9:16
*/
@Slf4j
public class Task extends TimerTask {
private SampleService sampleService;
private String env;
public Task(SampleService sampleService, String env) {
this.sampleService= sampleService;
this.env = env;
}
@Override
public void run() {
// do something
}
}
b 编写监听类
c 用ScheduledExecutorService调用任务
package com.xxx.awk.listener;
import com.xxx.awk.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author: youxingyang
* @date: 2018/8/30 9:09
*/
public class ContextListener implements ServletContextListener {
private ScheduledExecutorService pool = null;
public ContextListener() {
}
/**
* 初始化定时器
* web 程序运行时候自动加载
*/
public void contextInitialized(ServletContextEvent arg0) {
try {
//获取service
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext());
SampleService sampleService = (SampleService) webApplicationContext.getBean("sampleService");
// 设置一个定时器
pool = Executors.newScheduledThreadPool(1);
arg0.getServletContext().log("定时器已启动");
// 根据工程运行环境不同调取不同配置文件
String env = arg0.getServletContext().getInitParameter("spring.profiles.active");
if (StringUtils.isBlank(env)) {
env = "development";
}
/**
* 每2小时执行某个操作(如某个类,或方法)
*/
Task t2 = new Task(sampleService, env);
pool.scheduleAtFixedRate(t2, 30, 3600 * 2, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
arg0.getServletContext().log("任务调度表遇到异常: " + e.getMessage());
}
arg0.getServletContext().log("已经添加任务调度表");
}
/**
* 销毁
*/
public void contextDestroyed(ServletContextEvent arg0) {
pool.shutdown();
arg0.getServletContext().log("定时器销毁");
}
}
web.xml添加监听
<listener>
<listener-class>com.xxx.awk.listener.ContextListener</listener-class>
</listener>
小结
当工程运行起来时,定时器延时30秒后将每隔2小时运行一次。
题外话
如果工程生产环境采用了集群环境会涉及一个问题,定时器会被重复执行,可以采用分布式锁策略或者数据库乐观锁解决。