開啓定時任務的方式有幾種:包括quartz定時框架和java自帶Timer定時器,區別在於,quartz定時任務在程序報錯後能不斷執行,而在Timer定時任務中,程序一旦報錯,定時任務即不再執行,可根據需求選用。
前兩天工作需求,需要寫個定時任務去跑一些數據,我首先選擇的就是quartz定時器,不過後來因爲環境問題而改用了Timer定時器,下面簡單介紹一下兩種定時器的書寫。
1,quaetz定時器,需要在applicationContext.xml中進行一些配置,代碼如下:
<!-- 實現定時器任務-要調度的對象 -->
<bean id="jobBean" class="com.mer.listener.job.TimerJob" />
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="jobBean" />
<property name="targetMethod" value="execute" />
<!-- 將併發設置爲false -->
<property name="concurrent" value="false" />
</bean>
<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="jobDetail" />
<!-- 定時任務,每天凌晨2點執行一次 -->
<!-- <property name="cronExpression" value="0 0 2 * * ?" /> -->
<property name="cronExpression" value="0/5 * * * * ?" />
</bean>
<!-- 總管理類如果將lazy-init='false'那麼容器啓動就會執行調度程序 -->
<bean id="startQuertz" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false" >
<property name="triggers">
<list>
<!-- 作業調度器,list下可加入其他的調度器 -->
<ref bean="trigger" />
</list>
</property>
</bean>
<!-- 注入工具類,普通類中能夠調用server層方法 -->
<!-- <bean id="springContextUtil" class="com.mer.util.SpringContextUtil"></bean> -->
<bean id="springBeanFactoryUtils" class="com.mer.util.SpringBeanFactoryUtils"/>
配置完成後,只需在TimerJob中完成相關邏輯代碼即可,execute方法即爲定時任務執行方法,我的TimerJob類如下:
package com.mer.listener.job;
import org.springframework.context.ApplicationContext;import com.mer.service.BaseService;
import com.mer.service.cailanzidb.TranddelService;
import com.mer.util.LogUtil;
import com.mer.util.SpringBeanFactoryUtils;
import com.mer.util.SpringContextUtil;
public class TimerJob{
//使用工具類獲取bean,在普通類中調用service
LogUtil log = new LogUtil();
public void execute(){
try {
//菜市場 市區 查看數據功能 每天定時錄入交易數據到彙總表
System.out.println("定時器-----定時錄入交易彙總表");
baseService.insert("transInsertGM");
baseService.insert("transInsertFJ");
baseService.insert("transInsertDM");
} catch (Exception e) {
log.errinfoe("執行定時器導入菜市場數據報錯", e);
e.printStackTrace();
}
}
}
}
上面的quartz定時器就寫好了,最後別忘了導入quartz定時器的相關jar包哦,下面說一下我遇到的一個坑,這裏不屬於定時器編寫範圍。
因爲業務需求,定時器裏要調用service層的相關方法跑數據,但是因爲此類爲普通類,不能直接通過註解直接注入service,如果直接使用的花,會報錯baseService空指針。因此需要另外寫一個工具類,工具類代碼如下:
package com.mer.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 普通類調用Spring註解方式的Service層bean
* Created by HZC on 2015/10/21.
*/
public class SpringBeanFactoryUtils implements ApplicationContextAware {
private static ApplicationContext appCtx;
/**
* 此方法可以把ApplicationContext對象inject到當前類中作爲一個靜態成員變量。
*
* @param applicationContext ApplicationContext 對象.
* @throws BeansException
* @author hzc
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
appCtx = applicationContext;
}
/**
* 獲取ApplicationContext
*
* @return
* @author hzc
*/
public static ApplicationContext getApplicationContext() {
return appCtx;
}
/**
* 這是一個便利的方法,幫助我們快速得到一個BEAN
*
* @param beanName bean的名字
* @return 返回一個bean對象
* @author hzc
*/
public static Object getBean(String beanName) {
return appCtx.getBean(beanName);
}
}
此工具類需要在applicationContext.xml配置裏添加一行配置,如下:
<!-- 注入工具類,普通類中能夠調用server層方法 -->
<bean id="springBeanFactoryUtils" class="com.mer.util.SpringBeanFactoryUtils"/>
如果有遇到相同問題的小夥伴,可以借鑑一下這個工具類,親測可用。
2,好了,上面是使用quartz定時框架寫定時任務,下面講一下怎麼用java自帶的Timer定時器寫定時任務,
Timer定時器用到的是litener監聽器,所以需要在web.xml中將需要監聽的定時任務加入定時器,配置如下:
<listener>
<listener-class>com.mer.conn.InitServletListener</listener-class>
</listener>
然後在監聽類InitServletListener中完成相關代碼,如下:
package com.mer.conn;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.mer.service.cailanzidb.TranddelService;
import com.mer.util.LogUtil;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
*
*********************************************************.<br>
* [類名] InitServletListener <br>
* [描述] 項目初始化監聽器 <br>
* [作者] gw <br>
* [時間] 2016-1-9 下午9:48:07 <br>
*********************************************************.<br>
*/
public class InitServletListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent arg0) {
}
public void contextInitialized(ServletContextEvent sce) {
//獲取service
WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
final TranddelService tranddelService= (TranddelService) applicationContext.getBean("tranddelService");
LogUtil log = new LogUtil();
try {
//設置TimerTask
TimerTask task = new TimerTask() {
@SuppressWarnings("static-access")
@Override
public void run() {
//菜市場 市區 查看數據功能 每天定時錄入交易數據到彙總表
System.out.println("定時器-----定時錄入交易彙總表");
tranddelService.insert("transInsertGM");
tranddelService.insert("transInsertFJ");
tranddelService.insert("transInsertDM");
}
};
int dateSpan=24*60*60*1000;
//設置執行時間
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH)+1;//每天
//定製每天定時執行一次
calendar.set(year, month, day, 17,59,00); //時間設置 後三位是時分秒
Date date = calendar.getTime();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date));
Timer timer = new Timer();
//每天的date時刻執行task, 僅執行一次
timer.schedule(task, date,dateSpan);
Thread.sleep(1000); //延遲一秒執行
} catch (Exception e) {
log.errinfoe("執行定時器導入菜市場數據報錯", e);
e.printStackTrace();
}
}
}
項目啓動初始化監聽器之後,即進行了任務監聽。
後語:假如你跟我一樣有業務需求,要通過普通類調用service層或dao層方法,建議使用Timer定時器,因爲Timer和quartz的管理容器不同,所以在進行bean注入時,使用quartz會出現一些框架知識方面的坑,對此方面理解不太深的小夥伴,還是選擇Timer比較保險,比如我哈。