Spring源码学习之:@async 方法上添加该注解实现异步调用的原理
在我们使用spring框架的过程中,在很多时候我们会使用@async注解来异步执行某一些方法,提高系统的执行效率。今天我们来探讨下 spring 是如何完成这个功能的。
spring
在扫描bean的时候会扫描方法上是否包含@async的注解,如果包含的,spring会为这个bean动态的生成一个子类,我们称之为代理类(?),
代理类是继承我们所写的bean的,然后把代理类注入进来,那此时,在执行此方法的时候,会到代理类中,代理类判断了此方法需要异步执行,就不会调用父类
(我们原本写的bean)的对应方法。spring自己维护了一个队列,他会把需要执行的方法,放入队列中,等待线程池去读取这个队列,完成方法的执行,
从而完成了异步的功能。我们可以关注到再配置task的时候,是有参数让我们配置线程池的数量的。因为这种实现方法,所以在同一个类中的方法调用,添加@async注解是失效的!,原因是当你在同一个类中的时候,方法调用是在类体内执行的,spring无法截获这个方法调用。
那在深入一步,spring为我们提供了AOP,面向切面的功能。他的原理和异步注解的原理是类似的,spring在启动容器的时候,会扫描切面所定义的
类。在这些类被注入的时候,所注入的也是代理类,当你调用这些方法的时候,本质上是调用的代理类。通过代理类再去执行父类相对应的方法,那spring只
需要在调用之前和之后执行某段代码就完成了AOP的实现了!
那最后我们还有一个问题,spring是如何动态的生成某一个类的子类的?代理类?
阅读目录
简单介绍:
Spring为任务调度与异步方法执行提供了注解支持。通过在方法上设置@Async注解,可使得方法被异步调用。也就是说调用者会在调用时立即返回,而被调用方法的实际执行是交给Spring的TaskExecutor来完成。
开启@Async注解:
<task:annotation-driven executor="annotationExecutor" />
<!-- 支持 @Async 注解 -->
<task:executor id="annotationExecutor" pool-size="20"/>
同时加入<context:component-scan />扫描注解。
栗子:
为了比较,先来一个同步调用:
@Component
public class TestAsyncBean {
public void sayHello4() throws InterruptedException {
Thread.sleep(2 * 1000);//网络连接中 。。。消息发送中。。。
System.out.println("我爱你啊!");
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:/applicationContext.xml"})
public class TestAsync {
@Test
public void test_sayHello4() throws InterruptedException, ExecutionException {
System.out.println("你不爱我了么?");
testAsyncBean.sayHello4();
System.out.println("回的这么慢, 你肯定不爱我了, 我们还是分手吧。。。");
Thread.sleep(3 * 1000);// 不让主进程过早结束
}
}
输出结果:
你不爱我了么?
我爱你啊!
回的这么慢, 你肯定不爱我了, 我们还是分手吧。。。
同步调用会按代码顺序依次进行下去,如果哪里需要等待,那么就阻塞在那里,不再向下继续进行。
使用@Async的异步调用:
@Component
public class TestAsyncBean {
@Async
public void sayHello3() throws InterruptedException {
Thread.sleep(2 * 1000);//网络连接中 。。。消息发送中。。。
System.out.println("我爱你啊!");
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:/applicationContext.xml"})
public class TestAsync {
@Autowired
private TestAsyncBean testAsyncBean;
@Test
public void test_sayHello3() throws InterruptedException, ExecutionException {
System.out.println("你不爱我了么?");
testAsyncBean.sayHello3();
System.out.println("你竟无话可说, 我们分手吧。。。");
Thread.sleep(3 * 1000);// 不让主进程过早结束
}
}
输出结果:
你不爱我了么?
你竟无话可说, 我们分手吧。。。
我爱你啊!
异步调用,通过开启新的线程来执行调用的方法,不影响主线程。异步方法实际的执行交给了Spring的TaskExecutor来完成。
上面这种方式是没有返回值的,下面尝试有返回值的异步调用:
@Component
public class TestAsyncBean {
@Async
public String sayHello2() throws InterruptedException {
Thread.sleep(2 * 1000);//网络连接中 。。。消息发送中。。。
return "我爱你啊!";// 调用方调用后会立即返回,所以返回null
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:/applicationContext.xml"})
public class TestAsync {
@Autowired
private TestAsyncBean testAsyncBean;
@Test
public void test_sayHello2() throws InterruptedException, ExecutionException {
System.out.println("你不爱我了么?");
System.out.println(testAsyncBean.sayHello2());
System.out.println("你说的啥? 我们还是分手吧。。。");
Thread.sleep(3 * 1000);// 不让主进程过早结束
}
}
输出结果:
你不爱我了么?
null
你说的啥? 我们还是分手吧。。。
通过直接获取返回值得方式是不行的,这里就需要用到异步回调,异步方法返回值必须为Future<>,就像Callable与Future。
下面通过AsyncResult<>来获得异步调用的返回值:
@Component
public class TestAsyncBean {
@Async
public Future<String> sayHello1() throws InterruptedException {
int thinking = 2;
Thread.sleep(thinking * 1000);//网络连接中 。。。消息发送中。。。
System.out.println("我爱你啊!");
return new AsyncResult<String>("发送消息用了"+thinking+"秒");
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:/applicationContext.xml"})
public class TestAsync {
@Autowired
private TestAsyncBean testAsyncBean;
@Test
public void test_sayHello1() throws InterruptedException, ExecutionException {
Future<String> future = null;
System.out.println("你不爱我了么?");
future = testAsyncBean.sayHello1();
System.out.println("你竟无话可说, 我们分手吧。。。");
Thread.sleep(3 * 1000);// 不让主进程过早结束
System.out.println(future.get());
}
}
输出结果:
你不爱我了么?
你竟无话可说, 我们分手吧。。。
我爱你啊!
发送消息用了2秒
Spring源码学习之:@async 方法上添加该注解实现异步调用的原理的更多相关文章
- Spring @async 方法上添加该注解实现异步调用的原理
Spring @async 方法上添加该注解实现异步调用的原理 学习了:https://www.cnblogs.com/shangxiaofei/p/6211367.html 使用异步方法进行方法调用 ...
- @async 方法上添加该注解实现异步调用的原理
在我们使用spring框架的过程中,在很多时候我们会使用@async注解来异步执行某一些方法,提高系统的执行效率.今天我们来探讨下 spring 是如何完成这个功能的. spring 在扫描bean的 ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- spring源码学习之路---深入AOP(终)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...
- spring源码学习之路---IOC初探(二)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...
- Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md
写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...
- Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签
写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...
- Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件
写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...
- 【目录】Spring 源码学习
[目录]Spring 源码学习 jwfy 关注 2018.01.31 19:57* 字数 896 阅读 152评论 0喜欢 9 用来记录自己学习spring源码的一些心得和体会以及相关功能的实现原理, ...
随机推荐
- 使用Android点击按钮跳转页面
1.首先新建一个Android工程,命名为MyApp(名字可以自己随意起); 2.以原有的MainActivity.java文件为登录界面,然后在src文件中的包上面右击选择New目录下的Other中 ...
- Decorator
1 意图:动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更灵活. 2 别名:包装器Wrapper 3 动机:将组件嵌入到另一个对象中,由这个对象添加边框.嵌入的 ...
- jquery打字机效果
html代码 <div id="box"> <div id="content"> <div id="code" ...
- js输入,输出基本操作
- Javascript之运动框架2
运动框架2与运动框架1的不同之处在于,运动框架2是框架1的升级版,首先完善了传入值,改为move(obj,json,options),在options里面,可以选择传入或者不传入时间,运动形式,以及函 ...
- 【必备】史上最全的浏览器 CSS & JS Hack 手册(转)
浏览器渲染页面的方式各不相同,甚至同一浏览器的不同版本(“杰出代表”是 IE)也有差异.因此,浏览器兼容成为前端开发人员的必备技能.如果有一份浏览器 Hack 手册,那查询起来就方便多了.这篇文章就向 ...
- Python基本时间转换
时间转换 python中处理时间的时候,最常用的就是字符形式与时间戳之间的转换. 把最基本的转换在这里记下来 string -> timestamp import time import dat ...
- 使用Dottrace跟踪代码执行时间
当自己程序遇到性能问题,比如IIs请求反应缓慢,客户端程序执行缓慢,怎么分析是哪里出了问题呢?dottrace可以帮助.net程序跟踪出代码里每个方法的执行时间,这样让我们更清晰的看出是哪里执行时间过 ...
- .htaccess语法中RewriteCond和RewriteRule意义
今天看了301重定向设置的方法,对网站的首页权重有较重要意义.于是看了别人写的.htaccess文件发现一头雾水,于是查了一些资料来进一步理解. RewriteCond语法 RewriteCond T ...
- HTML5全局属性和事件
全局属性和事件能够应用到所有标签元素上,在HTML4中有许多全局属性,比如id,class等.HTML5中又新增了一些特殊功能的全局属性和事件. 属性: HTML5属性能够赋给标签元素含义和语 ...