在我们使用spring框架的过程中,在很多时候我们会使用@async注解来异步执行某一些方法,提高系统的执行效率。今天我们来探讨下 spring 是如何完成这个功能的。
spring 在扫描bean的时候会扫描方法上是否包含@async的注解,如果包含的,spring会为这个bean动态的生成一个子类,我们称之为代理类(?),代理类是继承我们所写的bean的,然后把代理类注入进来,那此时,在执行此方法的时候,会到代理类中,代理类判断了此方法需要异步执行,就不会调用父类(我们原本写的bean)的对应方法。spring自己维护了一个队列,他会把需要执行的方法,放入队列中,等待线程池去读取这个队列,完成方法的执行,从而完成了异步的功能。我们可以关注到再配置task的时候,是有参数让我们配置线程池的数量的。
因为这种实现方法,所以在同一个类中的方法调用,添加@async注解是失效的!,原因是当你在同一个类中的时候,方法调用是在类体内执行的,spring无法截获这个方法调用。
那在深入一步,spring为我们提供了AOP,面向切面的功能。他的原理和异步注解的原理是类似的,spring在启动容器的时候,会扫描切面所定义的类。在这些类被注入的时候,所注入的也是代理类,当你调用这些方法的时候,本质上是调用的代理类。通过代理类再去执行父类相对应的方法,那spring只需要在调用之前和之后执行某段代码就完成了AOP的实现了!
在spring 3中,@Async注解能让某个方法快速变为异步执行,马上来先DEMO上手下。
假如在网站的用户注册后,需要发送邮件,然后用户得到邮件确认后才能继续其他工作;
假设发送是一个很耗费时间的过程,因此需要异步。
1 namespace要注意,加上task
2 RegularService.java 注册类
1. <?xml version=”1.0″ encoding=”UTF-8″?>
2.
3. <beans xmlns=”http://www.springframework.org/schema/beans” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
4. xmlns:p=”http://www.springframework.org/schema/p” xmlns:context=”http://www.springframework.org/schema/context”
5. xsi:schemaLocation=”
6. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
8. http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd”>
9.
10. <context:component-scan base-package=”cs”/>
11.
12. </beans>
1. import
2. import
3.
4. import
5.
6. @Service
7. public class
8.
9. @Autowired
10. private
11.
12. public void
13.
14. System.out.println(” User registration for
15.
16. mailUtility.sendMail(userName);
17.
18. System.out.println(” 注册完成,邮件稍后发送“);
19. }
20.
21. }
22.
23. 3
24. import
25. import
26.
27. @Component
28. public class
29.
30. @Async
31. public void
32.
33. System.out.println(” 在做发送准备工作中 “);
34.
35. try
36. Thread.sleep(5000);
37.
38. } catch
39.
40. e.printStackTrace();
41. }
42.
43. System.out.println(” 异步发送完毕“);
44.
45. }
46.
47. }
48.
49.
50. 4
51. <?xml version=”1.0″ encoding=”UTF-8″?>
52.
53. <beans xmlns=”http://www.springframework.org/schema/beans” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
54. xmlns:p=”http://www.springframework.org/schema/p” xmlns:context=”http://www.springframework.org/schema/context”
55. xmlns:task=”http://www.springframework.org/schema/task”
56. xsi:schemaLocation=”
57. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
58. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
59. http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd“>
60.
61. <context:component-scan base-package=”cs”/>
62.
63. <task:annotation-driven/>
64.
65. </beans>
66. 就是<task:annotation-driven/>这个一定不能少喔。
67.
68. 5
69. for
70. 注册完成,邮件稍后发送
71. 在做发送准备工作中
72. 异步发送完毕
73.
74. 6
75. @Async
76. public Future<Balance> findBalanceAsync(final
77. Balance balance = accountRepository.findBalance(account);
78. return new
79. }
80.
81. Balance balance = future.get();
82.
Spring3中加强了注解的使用,其中计划任务也得到了增强,现在创建一个计划任务只需要两步就完成了:
- 创建一个Java类,添加一个无参无返回值的方法,在方法上用@Scheduled注解修饰一下;
- 在Spring配置文件中添加三个<task:**** />节点;
最后说明一下,第一步创建的Java类要成为Spring可管理的Bean,可以直接写在XML里,也可以@Component一下
示例如下
计划任务类:
1. /**
2. * com.zywang.spring.task.SpringTaskDemo.java
3. * @author ZYWANG 2011-3-9
4. */
5. package
6.
7. import
8. import
9.
10. /**
11. * Spring3 @Scheduled 演示
12. * @author ZYWANG 2011-3-9
13. */
14. @Component
15. public class
16.
17. @Scheduled(fixedDelay = 5000)
18. void
19. "I'm doing with delay now!");
20. }
21.
22. @Scheduled(fixedRate = 5000)
23. void
24. "I'm doing with rate now!");
25. }
26.
27. @Scheduled(cron = "0/5 * * * * *")
28. void
29. "I'm doing with cron now!");
30. }
31. }
Spring配置文件:
1. <?xml versinotallow="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
4. xsi:schemaLocatinotallow="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
5. >
6. <!-- Enables the Spring Task @Scheduled programming model -->
7. <task:executor id="executor" pool-size="5" />
8. <task:scheduler id="scheduler" pool-size="10" />
9. <task:annotation-driven executor="executor" scheduler="scheduler" />
10. </beans>
1. /**
2. * com.zywang.spring.task.SpringTaskDemo.java
3. * @author ZYWANG 2011-3-9
4. */
5. package
6.
7. import
8. import
9.
10. /**
11. * Spring3 @Scheduled 演示
12. * @author ZYWANG 2011-3-9
13. */
14. @Component
15. public class
16.
17. @Scheduled(fixedDelay = 5000)
18. void
19. "I'm doing with delay now!");
20. }
21.
22. @Scheduled(fixedRate = 5000)
23. void
24. "I'm doing with rate now!");
25. }
26.
27. @Scheduled(cron = "0/5 * * * * *")
28. void
29. "I'm doing with cron now!");
30. }
31. }
Spring配置文件:
1. <?xml versinotallow="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
4. xsi:schemaLocatinotallow="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
5. >
6. <!-- Enables the Spring Task @Scheduled programming model -->
7. <task:executor id="executor" pool-size="5" />
8. <task:scheduler id="scheduler" pool-size="10" />
9. <task:annotation-driven executor="executor" scheduler="scheduler" />
10. </beans>