在我们使用spring框架的过程中,在很多时候我们会使用@async注解来异步执行某一些方法,提高系统的执行效率。今天我们来探讨下 spring 是如何完成这个功能的。
spring 在扫描bean的时候会扫描方法上是否包含@async的注解,如果包含的,spring会为这个bean动态的生成一个子类,我们称之为代理类(?),代理类是继承我们所写的bean的,然后把代理类注入进来,那此时,在执行此方法的时候,会到代理类中,代理类判断了此方法需要异步执行,就不会调用父类(我们原本写的bean)的对应方法。spring自己维护了一个队列,他会把需要执行的方法,放入队列中,等待线程池去读取这个队列,完成方法的执行,从而完成了异步的功能。我们可以关注到再配置task的时候,是有参数让我们配置线程池的数量的。 因为这种实现方法,所以在同一个类中的方法调用,添加@async注解是失效的! ,原因是当你在同一个类中的时候,方法调用是在类体内执行的,spring无法截获这个方法调用。
那在深入一步,spring为我们提供了AOP,面向切面的功能。他的原理和异步注解的原理是类似的,spring在启动容器的时候,会扫描切面所定义的类。在这些类被注入的时候,所注入的也是代理类,当你调用这些方法的时候,本质上是调用的代理类。通过代理类再去执行父类相对应的方法,那spring只需要在调用之前和之后执行某段代码就完成了AOP的实现了!
那最后我们还有一个问题,spring是如何动态的生成某一个类的子类的?代理类?
生成代理类可以通过jdk 和 CGLIB 两种方式生成.具体的可以
参考 1.代理类说明: http://wenku.baidu.com/link?url=YpU3CNXsyLivMCnpILQ1qQc8PcKuqRrqZd1X8hPNQa9QuBFmbpCugSdjkXlY2L_ey4rUxM7TlwHeAatL65e664h_W8n0IKgTP1vFU5wacrm
2.CGLIB和JDK代理类的区别: http://www.blogjava.net/hello-yun/archive/2011/11/09/363359.html
这里就不详细说明了
spring 在扫描bean的时候会扫描方法上是否包含@async的注解,如果包含的,spring会为这个bean动态的生成一个子类,我们称之为代理类(?),代理类是继承我们所写的bean的,然后把代理类注入进来,那此时,在执行此方法的时候,会到代理类中,代理类判断了此方法需要异步执行,就不会调用父类(我们原本写的bean)的对应方法。spring自己维护了一个队列,他会把需要执行的方法,放入队列中,等待线程池去读取这个队列,完成方法的执行,从而完成了异步的功能。我们可以关注到再配置task的时候,是有参数让我们配置线程池的数量的。 因为这种实现方法,所以在同一个类中的方法调用,添加@async注解是失效的! ,原因是当你在同一个类中的时候,方法调用是在类体内执行的,spring无法截获这个方法调用。
那在深入一步,spring为我们提供了AOP,面向切面的功能。他的原理和异步注解的原理是类似的,spring在启动容器的时候,会扫描切面所定义的类。在这些类被注入的时候,所注入的也是代理类,当你调用这些方法的时候,本质上是调用的代理类。通过代理类再去执行父类相对应的方法,那spring只需要在调用之前和之后执行某段代码就完成了AOP的实现了!
那最后我们还有一个问题,spring是如何动态的生成某一个类的子类的?代理类?
生成代理类可以通过jdk 和 CGLIB 两种方式生成.具体的可以
参考 1.代理类说明: http://wenku.baidu.com/link?url=YpU3CNXsyLivMCnpILQ1qQc8PcKuqRrqZd1X8hPNQa9QuBFmbpCugSdjkXlY2L_ey4rUxM7TlwHeAatL65e664h_W8n0IKgTP1vFU5wacrm
2.CGLIB和JDK代理类的区别: http://www.blogjava.net/hello-yun/archive/2011/11/09/363359.html
这里就不详细说明了
在spring 3中,@Async注解能让某个方法快速变为异步执行,马上来先DEMO上手下。
假如在网站的用户注册后,需要发送邮件,然后用户得到邮件确认后才能继续其他工作;
假设发送是一个很耗费时间的过程,因此需要异步。
1 namespace要注意,加上task
2 RegularService.java 注册类
假如在网站的用户注册后,需要发送邮件,然后用户得到邮件确认后才能继续其他工作;
假设发送是一个很耗费时间的过程,因此需要异步。
1 namespace要注意,加上task
- <?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”
- 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-scan base- package =”cs”/>
- </beans>
2 RegularService.java 注册类
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import cs.async.MailUtility;
- @Service
- public class RegularService {
- @Autowired
- private MailUtility mailUtility ;
- public void registerUser(String userName){
- System.out.println(” User registration for “+userName +” complete”);
- mailUtility.sendMail(userName);
- System.out.println(” 注册完成,邮件稍后发送“);
- }
- }
- 3 发送邮件的工具类
- import org.springframework.scheduling.annotation.Async;
- import org.springframework.stereotype.Component;
- @Component
- public class MailUtility {
- @Async
- public void sendMail(String name){
- System.out.println(” 在做发送准备工作中 “);
- try {
- Thread.sleep( 5000 );
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(” 异步发送完毕“);
- }
- }
- 4 最后在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: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-scan base- package =”cs”/>
- <task:annotation-driven/>
- </beans>
- 就是<task:annotation-driven/>这个一定不能少喔。
- 5 运行:
- User registration for tom complete
- 注册完成,邮件稍后发送
- 在做发送准备工作中
- 异步发送完毕
- 6 有的时候,要从异步中返回值,这个时候,spring会返回一个java.util.concurrent.Future对象,要调用其中的get方法,比如
- @Async
- public Future<Balance> findBalanceAsync( final Account account) {
- Balance balance = accountRepository.findBalance(account);
- return new AsyncResult<Balance>(balance);
- }
- Balance balance = future.get();
-
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 * * * * *" )
- 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-driven executor = "executor" scheduler = "scheduler" />
- </ beans >