Spring3.0.6定时任务task:scheduled
项目使用的spring版本比较旧是3.0.6版本,由于需要进行定时任务,就决定使用Spring自带的scheduled task。
在网上找了很多文章,也查看了Spring3.0.6的官方文档,按照网上和文档所说,可以使用注解或者配置两种方法之一都行,但是我发现单独使用两种方法都不行,怎么配置任务都无法运行。
最后看到一篇文章说两种方法同时用,才成功执行定时任务,可能是个Bug,我试了下,同时使用注解和XML配置后,任务确实成功执行了。
XML配置中,只需要配置一个方法即可,其他方法也能跟着运行了,而且XML中配置的定时时间会被注解覆盖掉,只能先这么做了,期待高手解答原因。
难道真的是Spring3.0.6的Bug??
Spring配置如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:jee="http://www.springframework.org/schema/jee"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:task="http://www.springframework.org/schema/task"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
- http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"
- default-lazy-init="true" default-autowire="byName">
- <!-- 配置注解扫描 -->
- <context:annotation-config />
- <!-- 自动扫描的包名 -->
- <context:component-scan base-package="com.demo" />
- <!-- Spring定时器注解开关-->
- <task:annotation-driven />
- <!-- 此处对于定时时间的配置会被注解中的时间配置覆盖,因此,以注解配置为准 -->
- <task:scheduled-tasks scheduler="myScheduler">
- <task:scheduled ref="scheduledTaskManager" method="autoCardCalculate" cron="1/5 * * * * *"/>
- </task:scheduled-tasks>
- <task:scheduler id="myScheduler" pool-size="10"/>
- <aop:aspectj-autoproxy />
- <!-- 加载配置文件 -->
- <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <list>
- <value>classpath:config.properties</value>
- </list>
- </property>
- </bean>
- </beans>
执行任务的POJO类如下:
- package com.demo.schedule;
- import org.apache.log4j.Logger;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.scheduling.annotation.Scheduled;
- import org.springframework.stereotype.Component;
- import java.util.Date;
- /**
- * Created with IntelliJ IDEA.
- * Author:
- * Date: 2013-10-09 14:39
- * Function: Spring定时任务管理
- */
- @Component("scheduledTaskManager")
- public class ScheduledTaskManager {
- /**
- * cron表达式:* * * * * *(共6位,使用空格隔开,具体如下)
- * cron表达式:*(秒0-59) *(分钟0-59) *(小时0-23) *(日期1-31) *(月份1-12或是JAN-DEC) *(星期1-7或是SUN-SAT)
- */
- /**
- * 定时卡点计算。每天凌晨 02:00 执行一次
- */
- @Scheduled(cron = "0 0 2 * * *")
- public void autoCardCalculate() {
- System.out.println("定时卡点计算... " + new Date());
- }
- }
对于这个问题,期待高手解答,也希望大家能一起讨论下。
替换成Sping3.2.2之后,就可以直接在XML中配置,而不需要在方法上使用注解配置时间了。
感谢4楼,5楼解答:
问题在于Spring全局配置:default-lazy-init="true"
加上这一句启动的时候还怎么初始化,如果不想改这个配置,那在bean上加个注解
@Component("scheduledTaskManager")
@Lazy(value="false")
public class ScheduledTaskManager {
//TODO
}
来源:http://blog.csdn.net/zht666/article/details/12518711
//---------------------------------------------------------
【Spring】Spring的定时任务
> 参考的优秀文章
> 版本说明
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.2.14.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>spring-webflow</artifactId> <version>2.3.4.RELEASE</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.0</version> </dependency> </dependencies>
> 搭建最简单的Spring定时任务工程
Spring定时任务,给人的第一感觉就是简洁(>_<)
所需要的JAR,参考以上“版本说明”的POM文件,当然,不嫌麻烦,也可以一个个去下载。
把Spring通过web.xml注册进来
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring/spring.xml</param-value> </context-param> <listener> <description>Spring Context</description> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
当然,需要告诉Spring去哪儿扫描组件。对了,也要告诉Spring我们是使用注解方式注册任务的
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd"> <context:component-scan base-package="com.nicchagil.*"/> <task:annotation-driven/> </beans>
附logback的配置
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>D:/logs/application.log</file> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </root> </configuration>
好了,注册一个简单的任务,它每逢0秒执行,打印一个语句
package com.nicchagil.springtask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class MyFirstSpringJob {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Scheduled(cron = "0 * * * * ?")
public void run() {
logger.info("MyFirstSpringJob trigger...");
}
}
如无意外,启动项目后,可见日志大致如下
22:42:00.024 [pool-1-thread-1] INFO c.n.springtask.MyFirstSpringJob - MyFirstSpringJob trigger...
22:43:00.002 [pool-1-thread-1] INFO c.n.springtask.MyFirstSpringJob - MyFirstSpringJob trigger...
> 如果你同时执行多个任务,且某些任务耗时较长,要配线程池哦(>_<)
如题。比如,你设置了12:00触发A任务、12:05触发B任务,如果A任务需耗时10分钟,并且没设置线程池,那么B任务有可能会被推迟到12:10以后再执行哦。
所以,这些情况,我们需设置线程池
<task:annotation-driven scheduler="myScheduler"/> <task:scheduler id="myScheduler" pool-size="20"/>
注:具体池的大小,视项目情况而定
将任务改为如下测试
第一个任务
package com.nicchagil.springtask; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class MyFirstSpringJob { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Scheduled(cron = "0 * * * * ?") public void run() { logger.info("MyFirstSpringJob trigger..."); /* 模拟此Job需耗时5秒 */ try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } } }
第二个任务
package com.nicchagil.springtask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class MySecondSpringJob { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Scheduled(cron = "3 * * * * ?") public void run() { logger.info("MySecondSpringJob trigger..."); } }
由日志可以看出,第一个任务由一个线程执行;而第二个任务启动时,由于第一个任务还未完成,则由另外一个线程执行
22:49:00.023 [myScheduler-1] INFO c.n.springtask.MyFirstSpringJob - MyFirstSpringJob trigger... 22:49:03.002 [myScheduler-2] INFO c.n.springtask.MySecondSpringJob - MySecondSpringJob trigger...