spring 3中的@async初探
-
- <P>@RunWith(SpringJUnit4ClassRunner.class)</P>@ContextConfiguration(locations = { "/spring/*.xml" })
- public class JobUtilsTest{
- @Autowired
- private DaoService service;
- @Test
- public void testAsync()throws Exception {
- System.out.println("start" );
- service.update(); // ★ 假设这个方法会比较耗时,需要异步执行
- System.out.println("end");
- Thread.sleep(3000); // 因为junit结束会结束jvm,所以让它等会异步线程
- }
- }
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/spring/*.xml" }) public class JobUtilsTest{@Autowiredprivate DaoService service;@Testpublic void testAsync() throws Exception {System.out.println("start" );service.update(); // ★ 假设这个方法会比较耗时,需要异步执行System.out.println("end");Thread.sleep(3000); // 因为junit结束会结束jvm,所以让它等会异步线程} }DaoService代码:
- @Service
- public class DaoService {
- @Async
- public void update() {
- try {
- Thread.sleep(2000);
- // do something
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("operation complete.");
- }
- }
@Service public class DaoService {@Asyncpublic void update() {try {Thread.sleep(2000);// do something} catch (InterruptedException e) {e.printStackTrace();}System.out.println("operation complete.");} }
applicationContext.xml
- <?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:p="http://www.springframework.org/schema/p"
- xmlns:context="http://www.springframework.org/schema/context"
- 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.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
- <context:component-scanbase-package="com.chinacache"/>
- <task:annotation-driven/>
- </beans>
<?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:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"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.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"><context:component-scan base-package="com.chinacache" /><task:annotation-driven /></beans>
输出结果:
start
end
operation complete.
可以看出,输出不是顺序执行,说明异步调用成功了。
Spring 配置管理 Bean XML
Spring3中加强了注解的使用,其中计划任务也得到了增强,现在创建一个计划任务只需要两步就完成了:
- 创建一个Java类,添加一个无参无返回值的方法,在方法上用@Scheduled注解修饰一下;
- 在Spring配置文件中添加三个<task:**** />节点;
最后说明一下,第一步创建的Java类要成为Spring可管理的Bean,可以直接写在XML里,也可以@Component一下
示例如下
计划任务类:
- /**
- * com.zywang.spring.task.SpringTaskDemo.java
- * @author ZYWANG 2011-3-9
- */
- package com.zywang.spring.task;
- import org.springframework.scheduling.annotation.Scheduled;
- import org.springframework.stereotype.Component;
- /**
- * Spring3 @Scheduled 演示
- * @author ZYWANG 2011-3-9
- */
- @Component
- public class SpringTaskDemo {
- @Scheduled(fixedDelay = 5000)
- void doSomethingWithDelay(){
- System.out.println("I'm doing with delay now!");
- }
- @Scheduled(fixedRate = 5000)
- void doSomethingWithRate(){
- System.out.println("I'm doing with rate now!");
- }
- @Scheduled(cron = "0/5 * * * * *") 每5称执行一次
- void doSomethingWith(){
- System.out.println("I'm doing with cron now!");
- }
- }
/*** com.zywang.spring.task.SpringTaskDemo.java* @author ZYWANG 2011-3-9*/
package com.zywang.spring.task;import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;/*** Spring3 @Scheduled 演示* @author ZYWANG 2011-3-9*/
@Component
public class SpringTaskDemo {@Scheduled(fixedDelay = 5000)void doSomethingWithDelay(){System.out.println("I'm doing with delay now!");}@Scheduled(fixedRate = 5000)void doSomethingWithRate(){System.out.println("I'm doing with rate now!");}@Scheduled(cron = "0/5 * * * * *")void doSomethingWith(){System.out.println("I'm doing with cron now!");}
}
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:task="http://www.springframework.org/schema/task"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
- <!-- Enables the Spring Task @Scheduled programming model -->
- <task:executor id="executor" pool-size="5" />
- <task:scheduler id="scheduler" pool-size="10" />
- <task:annotation-drivenexecutor="executor"scheduler="scheduler"/>
- </beans>
- CRON表达式 含义
"0 0 12 * * ?" 每天中午十二点触发
"0 15 10 ? * *" 每天早上10:15触发
"0 15 10 * * ?" 每天早上10:15触发
"0 15 10 * * ? *" 每天早上10:15触发
"0 15 10 * * ? 2005" 2005年的每天早上10:15触发
"0 * 14 * * ?" 每天从下午2点开始到2点59分每分钟一次触发
"0 0/5 14 * * ?" 每天从下午2点开始到2:55分结束每5分钟一次触发
"0 0/5 14,18 * * ?" 每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发
"0 0-5 14 * * ?" 每天14:00至14:05每分钟一次触发
"0 10,44 14 ? 3 WED" 三月的每周三的14:10和14:44触发
"0 15 10 ? * MON-FRI" 每个周一、周二、周三、周四、周五的10:15触发
- <br>
项目使用的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>
<?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.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://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());
- }
- /**
- * 心跳更新。启动时执行一次,之后每隔1分钟执行一次
- */
- @Scheduled(fixedRate = 1000*60*1)
- public void heartbeat() {
- System.out.println("心跳更新... " + new Date());
- }
- /**
- * 卡点持久化。启动时执行一次,之后每隔2分钟执行一次
- */
- @Scheduled(fixedRate = 1000*60*2)
- public void persistRecord() {
- System.out.println("卡点持久化... " + new Date());
- }
- }