之前我用JAVA中的Timer類實現了服務器的定時任務,具體詳見之前的博文。
后來發現了一個更簡單的實現方式,利用spring中的@Scheduled注解實現覺得簡單的很多。
確實spring封裝的特別好,實現起來比原來簡單多了。
下面是配置。
在spring的xml配置中最上面加入
xmlns:task=http://www.springframework.org/schema/task
xsi:schemaLocation中加入
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd
在后面加入
<!-- 用於定時器的配置 -->
<task:annotation-driven/>
最后寫一個定時器的類就行了,寫法可以和controller類似,上面的注解不一樣而已
@Component public class TimeTask { @Autowired public IUserService userService; @Scheduled(cron="0/5 * * * * ? ") public void test() { System.out.println("11111111111111111111111111111111111"); } }
然后運行項目你就能發現每5秒執行一次
然后發現兩個使用上面的問題。
問題1:如果配置了多個定時任務,當有任務1執行時間過長的時候會阻塞任務2
如下面所示
@Component public class TimeTask { @Autowired public IUserService userService; @Scheduled(cron="0/5 * * * * ? ") public void test() { System.out.println("11111111111111111111111111111111111"); } @Scheduled(cron="0/1 * * * * ? ") public void test2() throws InterruptedException { TimeUnit.SECONDS.sleep(10);//模擬延時10秒 System.out.println("222222222222222222222222222222222"); } }
你會發現11111和22222是同時打印的,1111並不是5秒打印一次了。所以你需要配置線程池。
把之前的spring中的配置修改為下面這樣,20是線程池的大小,根據具體項目需求來設置。
<task:annotation-driven scheduler="myScheduler"/>
<task:scheduler id="myScheduler" pool-size="20"/>
問題2,定時任務莫名其妙被執行兩次。
一開始就發現了這個問題,莫名其妙會輸出111111和111111兩次。連續兩次。
就相當任務被同時執行了兩次,一開始我覺得奇怪,但是后來查詢資料發現了我的一個大問題。
在web。xml中加載了兩次相同的spring配置
就相當於spring的上下文被創建了兩次,導致定時任務也就創建了兩次,所以導致這個問題的發生
一開始的配置
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:config/applicationContext.xml</param-value> </context-param> <servlet> <servlet-name>springMVC_dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:config/applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
加載兩個applicationContext
后面修改成了兩個配置文件
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:config/beans.xml</param-value> </context-param> <servlet> <servlet-name>springMVC_dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:config/applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
一個加載定時器和controller的相關配置,一個加載數據庫相關配置。
然后就解決了。
下面是stackoverflow中對這個問題的描述
http://stackoverflow.com/questions/3672289/spring-3-scheduled-task-running-3-times
深層次的原因可以看我的另一篇博文
http://www.cnblogs.com/linkstar/p/5782027.html
下面轉載一個定時器時間上面的配置,因為定時器的時間配置不好記,所以暫時記錄一下,和linux上面的定時任務很像。
http://rainbowdesert.iteye.com/blog/2107220
最后是spring官網的文檔,我沒看,英文不好
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html