@Async java 异步方法

  在spring 3中,@Async注解能让某个方法快速变为异步执行,立刻来先DEMO上手下。 

假如在网站的用户注册后,须要发送邮件,而后用户获得邮件确认后才能继续其余工做; 
假设发送是一个很耗费时间的过程,所以须要异步。 

1 namespace要注意,加上task 
  html

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>  



2 RegularService.java 注册类 
  java

Java代码   收藏代码
    1.  import org.springframework.beans.factory.annotation.Autowired;  
    2. import org.springframework.stereotype.Service;  
    3.   
    4. import cs.async.MailUtility;  
    5.   
    6. @Service  
    7. public class RegularService {  
    8.   
    9. @Autowired  
    10. private MailUtility mailUtility ;  
    11.   
    12. public void registerUser(String userName){  
    13.   
    14. System.out.println(” User registration for  “+userName +” complete”);  
    15.   
    16. mailUtility.sendMail(userName);  
    17.   
    18. System.out.println(” 注册完成,邮件稍后发送“);  
    19. }  
    20.   
    21. }  
    22.   
    23. 3 发送邮件的工具类  
    24.    <pre name="code" class="java">import org.springframework.scheduling.annotation.Async;  
    25. import org.springframework.stereotype.Component;  
    26.   
    27. @Component  
    28. public class MailUtility {  
    29.   
    30. @Async  
    31. public void sendMail(String name){  
    32.   
    33. System.out.println(” 在作发送准备工做中  “);  
    34.   
    35. try {  
    36. Thread.sleep(5000);  
    37.   
    38. catch (InterruptedException e) {  
    39.   
    40. e.printStackTrace();  
    41. }  
    42.   
    43. System.out.println(” 异步发送完毕“);  
    44.   
    45. }  
    46.   
    47. }  
    48. </pre>  
    49. <br>  
    50. <br>4 最后在applicationContext.xml中加入:  
    51. <br>  <pre name="code" class="java"><?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. </pre>  
    67. <br>   就是<task:annotation-driven/>这个必定不能少喔。  
    68. <br>  
    69. <br>5 运行:  
    70. <br>   User registration for  tom complete  
    71. <br>  注册完成,邮件稍后发送  
    72. <br>在作发送准备工做中  
    73. <br>异步发送完毕  
    74. <br>  
    75. <br>6 有的时候,要从异步中返回值,这个时候,spring会返回一个java.util.concurrent.Future对象,要调用其中的get方法,好比  
    76. <br>   <pre name="code" class="java">@Async  
    77. public Future<Balance> findBalanceAsync(final Account account) {  
    78.     Balance balance = accountRepository.findBalance(account);  
    79.     return new AsyncResult<Balance>(balance);  
    80. }  
    81.   
    82. Balance balance = future.get();  
    83.   
    84. </pre>  
    85. <br>     
    86. <br>  
    87. 注意事项:必须解决循环依赖
    88. 原理: spring 在扫描bean的时候会扫描方法上是否包含@async的注解,若是包含的,spring会为这个bean动态的生成一个子类,咱们称之为代理类(?),代理类是继承咱们所写的bean的,而后把代理类注入进来,那此时,在执行此方法的时候,会到代理类中,代理类判断了此方法须要异步执行,就不会调用父类(咱们本来写的bean)的对应方法。spring本身维护了一个队列,他会把须要执行的方法,放入队列中,等待线程池去读取这个队列,完成方法的执行,从而完成了异步的功能。
    89. 今天对项目工程(spring3.0.6+structs2.2.3)进行瘦身,业务层bean统一用@Service注解,set注入用@Autowired替换,从xml配置文件中将业务bean配置所有清掉。
      这时专门处理异步操做的bean报循环依赖(引用):
      Bean with name ‘*********’ has been injected into other beans [******, **********, **********, **********] in its raw version as part of a circular reference具体状况是beanA注入用于异步处理的beanB(含有@Async注解的方法),用于对某些操做进行异步处理,而beanB又注入beanA用于实现异步处理
      解决方案:beanA注入异步处理的beanB的代理服务beanC(不含@Async注解),再由beanC注入beanB进行处理spring