- public class DoJob{
- //...
- public void execute(){...}
- }
配置也很簡單
- <bean id="doJobDetail(對應類起個名)" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
- <property name="targetObject">
- <ref bean="doJobBean(DoJob對應配置的bean)"/>
- </property>
- <property name="targetMethod">
- <value>executeUpdate</value>
- </property>
- </bean>
- <bean id="doJobCronTrigger(觸發器)" class="org.springframework.scheduling.quartz.CronTriggerBean">
- <property name="jobDetail">
- <ref bean="doJobDetail(對應上面的bean)" />
- </property>
- <property name="cronExpression">
- <value>0 5 0 * * ?</value> //數字分別對應秒、分、時、日、月、星期、年(可選)
- </property>
- </bean>
- <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
- <property name="triggers">
- <list>
- <ref local="voteCronTrigger" />
- <ref local="updateLotteryCronTrigger" />
- </list>
- </property>
- </bean>
spring定時器用Annotation實現
由於項目中需要定時更新一些數據,所以用到了spring的定時器,在使用Quartz過程中,遇到了一些麻煩,最終牽扯的錯誤太多:
1、我的一個Service類中需要加入定時執行即Service extends QuartzJobBean,但是Service類中使用@Autowired注入了屬性:dao對象
2、在executeInternal方法執行過程中,dao對象一直爲null。
3、嘗試了各種辦法,最終在配置文件中這樣配置(這種配置網上多的是)
使用jobDataAsMap這個屬性
<bean id="quartzClock" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>org.wapgame.service.charts.Service</value>
</property>
<property name="jobDataAsMap">
<map>
<entry key="dao" value-ref="Dao"/>
<entry key="test" value="30"/>
</map>
</property>
</bean>
4、executeInternal方法中使用其參數來獲得值。
protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
// TODO Auto-generated method stub
JobDataMap map=arg0.getMergedJobDataMap();
int test = Integer.parseInt(map.get("test").toString());
log.debug("test:"+test);
playerDao=(PlayerDao)map.get("playerDao");
}
這樣就解決了注入的對象爲null的問題。網上找了好多找不到解決的辦法,最終還得靠自己。
5、解決是解決了,但是過程中我需要用到事務操作。隨之帶來了很大的麻煩,畢竟項目用的都是Annotaion,再加上自己在ApplicationContext.xml中配置,造成了很多麻煩和異常。
6、放棄,轉Annotation
通過 註解 來調度任務
1、
AnnotationQuartz類:
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class AnnotationQuartz {
@Scheduled(cron="0,10,20,30,40,50 * * * * ?") //需要注意@Scheduled這個註解,它可配置多個屬性:cron\fixedDelay\fixedRate
public void test()
{
System.out.println("0.0");
}
}
2、
spring的ApplicationContext.xml中的配置:
只需要加上
<!-- 定時器開關 開始-->
<task:annotation-driven/>
<!-- 定時器開關 結束-->
3、(如果是web應用,那麼需要再web.xml中加入)
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
通過 配置文件 來調度任務
1、
AnnotationQuartz類:
import org.springframework.stereotype.Component;
@Component(如果你的項目使用的是註解而不是配置文件中寫bean,那麼需要加上@Component,確保這個類已經注入)
public class AnnotationQuartz {
public void test()
{
System.out.println("0.0");
}
}
2、
spring的ApplicationContext.xml中的配置:
<task:scheduled-tasks>
<task:scheduled ref="chartsService" method="test" cron="0 0,15,30,45 * * * ?"/>
</task:scheduled-tasks>
最後請注意 :(ApplicationContext.xml)
a)、需要在xmlns裏面加入:
xmlns:task="http://www.springframework.org/schema/task"
b)、在xsi:schemaLocation中加入
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd(別忘了最後的引號)
cron表達式去搜吧,好多,我搜到了一些,如下:
<!--
一個cron表達式有到少6個(也可能是7個)由空格分隔的時間元素.從左到右,這些元素的定義如下:
1.秒(0-59)
2.分鐘(0-59)
3.小時(0-23)
4.月份中的是期(1-31)
5.月份(1-12或SUN-DEC)
6.星期中的日期(1-7或SUN-SAT)
7.年份(1970-2099)
例子:
0 0 10,14,16 * * ? 每天上午10點,下午2點和下午4點
0 0,15,30,45 * 1-10 * ? 每月前10天每隔15分鐘
30 0 0 1 1 ? 2012 在2012年1月1日午夜過30秒時
0 0 8-5 ? * MON-FRI 每個工作日的工作時間
- 區間
* 通配符
? 你不想設置那個字段
-->
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.bankcomm.util.ContextUtil;
public class QuartzCacheHandler {
private static ApplicationContext actx;
Log log = LogFactory.getLog( this .getClass());
/**
* 程序載入配置文件<br>
* Author:pesome<br>
* Time:2006-12-8 上午10:29:26<br>
*/
public static void init() {
try {
actx = new ClassPathXmlApplicationContext(
new String[] { " quartzCache*.xml " } );
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
private QuartzCacheHandler() {
}
/**
* 在程序載入配置文件時使用<br>
* Author:pesome<br>
* Time:2006-12-8 上午10:28:07<br>
*
* @param beanName
* @param key
* @return
*/
public static Object getSe(String beanName, String key) {
return ((QuartzCache) actx.getBean(beanName)).get(key);
}
/**
* 在web容器中,初始化時載入配置文件時使用<br>
* Author:pesome<br>
* Time:2006-12-8 上午10:28:40<br>
*
* @param beanName
* @param key
* @return
*/
public static Object get(String beanName, String key) {
return ((QuartzCache) ContextUtil.getBean(beanName)).get(key);
}
}
-----------------------------------QuartzCache-----------------------------------------------
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public abstract class QuartzCache {
private Log log = LogFactory.getLog( this .getClass());
protected Map cacheMap = new HashMap();
/**
* 抽象方法由具體的cache類實現,一般爲調用put方法<br>
* Author:pesome<br>
* Time:2006-12-7 下午05:47:26<br>
*/
public abstract void refresh();
public Object get(String key) {
return cacheMap.get(key);
}
public void put(String key, Object value) {
cacheMap.put(key, value);
log.info( " put to quartz cache key= " + key + " ,value= " + value);
}
}
---------------------------------------------------------------------------------------------------------
Web.xml 中只需加 2 句:
< param-name > contextConfigLocation </ param-name >
< param-value > /WEB-INF/applicationContext*.xml </ param-value >
</ context-param >
< listener >
< listener-class >
com.bankcomm.util.MyContextLoaderListener
</ listener-class >
</ listener >
最後是applicationContext_quartzCache.xml配置文件,就是標準的spring結合quartz的配置文件:
<! DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd" >
< beans >
< bean
class ="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
< property name ="triggers" >
< list >
< ref local ="simpleTrigger" />
</ list >
</ property >
</ bean >
< bean id ="methodInvokingJobDetail"
class ="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" >
< property name ="targetObject" >
< ref bean ="simpleCache" />
</ property >
< property name ="targetMethod" >
< value > refresh </ value >
</ property >
</ bean >
< bean id ="simpleTrigger"
class ="org.springframework.scheduling.quartz.SimpleTriggerBean" >
< property name ="jobDetail" >
<!-- see the example of method invoking job above -->
< ref bean ="methodInvokingJobDetail" />
</ property >
< property name ="startDelay" >
< value > 0 </ value >
</ property >
<!-- set the refresh interval,millisecond -->
< property name ="repeatInterval" >
< value > 2000 </ value >
</ property >
</ bean >
<!-- custom job beans -->
< bean id ="simpleCache" class ="com.bankcomm.cache.SimpleCache" ></ bean >
</ beans >
寫自己的QuartzCache子類並實現refresh方法,然後在配置文件中定義bean和相應的trigger就能方便的實現定時cache了。示例中使用了SimpleTriggerBean ,每2s更新一次。也可以使用CronTriggerBean,每天定時更新。 使用 cache ,只需調用 QuartzCacheHandler 的 get 和 getSe就行, get 是在由 web 容器啓動 quartz 的場合使用, getSe 在使用 init 方法啓動時使用。 Get 中調用了自己寫的一個 ContextUtil ,它包含一個靜態的 applicationContex 的引用,在 spring 容器啓動後由 MyContextLoaderListener (重載 spring 的 ContextLoaderListener )填充。
這些東西也就幾個小時搞定,多虧了spring,quartz這些開源軟件啊。要自己用timer實現,費時費力,擴展性,易用性等也會差很多。