之前我用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