一、什么是异步调用?


1.同步调用

方法间的调用,假设A方法调用B方法,A方法等待B方法执行完毕后才执行本身,这个同步调用,是具有阻塞式的调用,如果B方法非常耗时,那么整个方法的执行效率将会非常低;

2.异步调用

同样是方法间的调用,假设A方法调用B方法,不同的是A方法调用B方法后,B方法很快的返回给A方法个答复(这个答复不是执行完整个B方法的答复),A方法收到答复后就执行本身,这个是异步调用,不管B方法是否耗时,整体的效率都提升。

二、motan的异步调用入门


1.首先,以入门案例为基础案例改造:http://www.cnblogs.com/Json1208/p/8784906.html

2.motan-api工程HelloWorldService添加注解@MotanAsync

package com.motan.service;import com.weibo.api.motan.transport.async.MotanAsync;@MotanAsync
public interface HelloWorldService {String hello(String name);
}

3.motan-api添加maven插件build-helper-maven-plugin,用来把自动生成类的目录设置为source path

<build><plugins><plugin><groupId>org.codehaus.mojo</groupId><artifactId>build-helper-maven-plugin</artifactId><version>1.10</version><executions><execution><phase>generate-sources</phase><goals><goal>add-source</goal></goals><configuration><sources><source>${project.build.directory}/generated-sources/annotations</source></sources></configuration></execution></executions></plugin></plugins></build>

编译时,Motan自动生成异步service类,生成路径为target/generated-sources/annotations/,生成的类名为service名加上Async,例如service类名为HelloWorldService.java,则自动生成的类名为HelloWorldServiceAsync.java。

另外,需要将motan自动生产类文件的路径配置为项目source path,可以使用maven plugin或手动配置,以上使用maven plugin方式。

这样,我们就能在eclipse中的source folder 中生成HelloWorldServiceAsync.java。

4.motan-client.xml配置的motan:referer标签中配置interface为自动生成的以Async为后缀的对应service类

<motan:referer id="helloWorldReferer" interface="com.motan.service.HelloWorldServiceAsync" directUrl="localhost:8002"/>

5.测试,先启动server,再启动client

public class Server {@SuppressWarnings({ "unused", "resource" })public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:motan-server.xml");System.out.println("server start...");}
}log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
server start...

public class Client {@SuppressWarnings("resource")public static void main(String[] args) throws InterruptedException {ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"classpath:motan-client.xml"});HelloWorldServiceAsync async = (HelloWorldServiceAsync) ctx.getBean("helloWorldReferer");System.out.println(async.hello("motan"));}
}log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
Hello motan!

最后再来看server的控制台,如果成功调用,会输出方法结果:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
server start...
motan

三、motan异步调用详解


1.使用ResponseFuture接口来接收远程调用结果,ResponseFuture具备future和callback能力

①.将接口实现修改为:

package com.motan.service;public class HelloWorldServiceImpl implements HelloWorldService{@Overridepublic String hello(String name) {try {Thread.sleep(5000);        System.out.println(name);System.out.println("等待5s后返回");} catch (InterruptedException e) {e.printStackTrace();}return "Hello " + name + "!";}}

②.修改客户端调用为:

package com.motan.client;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.motan.service.HelloWorldServiceAsync;
import com.weibo.api.motan.rpc.ResponseFuture;public class Client {@SuppressWarnings("resource")public static void main(String[] args) throws InterruptedException {ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"classpath:motan-client.xml"});HelloWorldServiceAsync async = (HelloWorldServiceAsync) ctx.getBean("helloWorldReferer");ResponseFuture future = async.helloAsync("ResponseFuture");System.out.println(future.getValue());}
}

注意:为了防止接口调用超时,消费端需要配置调用超时时间,在motan-client.xml中配置:

<motan:referer id="helloWorldReferer" interface="com.motan.service.HelloWorldServiceAsync" directUrl="localhost:8002" connectTimeout="8000" requestTimeout="8000"/>

③.启动服务端

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
server start...

④.启动客户端

等待5s后服务端控制台打印:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
server start...
ResponseFuture
等待5s后返回

客户端控制台打印:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
Hello ResponseFuture!

2.使用FutureListener监听,该监听器可以监听到接口是否成功调用,可以很灵活的判断如果成功调用在输出相关调用返回信息

虽然ResponseFuture带有isDone和isSuccess,但是经过测试,isDone和isSuccess并没办法在异步调用后用于判断,而是得配合FutureListener一起使用:

①.service实现不变,仍然是带有休眠的效果:

package com.motan.service;public class HelloWorldServiceImpl implements HelloWorldService{@Overridepublic String hello(String name) {try {Thread.sleep(5000);System.out.println(name);System.out.println("等待5s后返回");} catch (InterruptedException e) {e.printStackTrace();}return "Hello " + name + "!";}}

②.使用FutureListener监听server端是否执行成功

package com.motan.client;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.motan.service.HelloWorldServiceAsync;
import com.weibo.api.motan.rpc.Future;
import com.weibo.api.motan.rpc.FutureListener;
import com.weibo.api.motan.rpc.ResponseFuture;public class Client {@SuppressWarnings("resource")public static void main(String[] args) throws InterruptedException {ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"classpath:motan-client.xml"});HelloWorldServiceAsync async = (HelloWorldServiceAsync) ctx.getBean("helloWorldReferer");FutureListener listener = new FutureListener() {@Overridepublic void operationComplete(Future future) throws Exception {System.out.println("async call "+ (future.isSuccess() ? "sucess! value:" + future.getValue() : "fail! exception:"+ future.getException().getMessage()));}};ResponseFuture future1 = async.helloAsync("motan FutureListener...");future1.addListener(listener);}
}

③.测试

首先,执行server端启动程序:

package com.motan.server;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Server {@SuppressWarnings({ "unused", "resource" })public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:motan-server.xml");System.out.println("server start...");}
}log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
server start...

接着,启动client端启动程序:

等待5s之后,server控制台输出:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
server start...
motan FutureListener...
等待5s后返回

再来看client控制台输出:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
async call sucess! value:Hello motan FutureListener...!

注意:在server端休眠的时候,client端是阻塞着的,由于我们超时时间跟上方一致配置的是8s,所以并不会超时,导致client一致阻塞,我们试着把超时实际调为3s(比server休眠时间短):

<?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:motan="http://api.weibo.com/schema/motan"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://api.weibo.com/schema/motan http://api.weibo.com/schema/motan.xsd"><!-- 具体referer配置。使用方通过beanid使用服务接口类 --><motan:referer id="helloWorldReferer" interface="com.motan.service.HelloWorldServiceAsync" directUrl="localhost:8002" connectTimeout="3000" requestTimeout="3000"/>
</beans>

重新启动server应用程序,server控制台输出:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
server start...

还未到休眠5s执行结束,client端就抛出一个异常:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
async call fail! exception:error_message: com.weibo.api.motan.rpc.DefaultResponseFuture task cancel: serverPort=localhost:8002 requestId=1597643022347010049 interface=com.motan.service.HelloWorldService method=hello(java.lang.String) cost=3042, status: 503, error_code: 10001,r=null

最后,server端才把休眠之后的消息打印:

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
server start...
motan FutureListener...
等待5s后返回

说明:client使用监听器监听server是否执行完毕,若server实际执行业务的时间在client端配置的接口请求超时时间之内,那么client请求后会一致阻塞着,直到server实际业务执行完成返回;

若server实际执行业务的时间大于client端配置的接口请求超时时间,那么一旦到达超时时间,直接抛出异常。

转载于:https://www.cnblogs.com/Json1208/p/8799370.html

3.motan之异步调用相关推荐

  1. springboot 多线程_SpringBoot异步调用@Async

    一. 什么是异步调用? 异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行. 二. 如何实现异步调用 ...

  2. C++多线程:package_task异步调用任何目标执行操作

    文章目录 描述 函数成员及使用 总结 我们上一篇描述关于C++多线程中的异步操作相关库( async和 promise),本节将分享c++标准库中最后一个多线程异步操作库 package_task的学 ...

  3. springboot之异步调用@Async

    引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...

  4. 异步调用WCF的方法需要小心的地方

    直接使用下面的代码,由于client对象占用的资源没有被释放,会导致内存泄露 GetSimServiceReference.GetSimServiceClient client = new GetSi ...

  5. 关于webservice的异步调用简单实例

    于webservice的异步调用简单实例 无论在任何情况下,被调用方的代码无论是被异步调用还是同步调用的情况下,被调用方的代码都是一样的, 下面,我们就以异步调用一个webservice 为例作说明. ...

  6. Spring Boot 中使用@Async实现异步调用,加速任务执行!

    欢迎关注方志朋的博客,回复"666"获面试宝典 什么是"异步调用"?"异步调用"对应的是"同步调用",同步调用指程序按照 ...

  7. Spring Boot 异步请求和异步调用

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 一.Spring Boot中异步请求的使用 1.异步请求与同步请求 ...

  8. xml提示无法连接到远程服务器,异步调用WebService时,如何捕捉“无法连接远程服务器”异常...

    在winform窗体中调用webservice,过程如下: ①Form1中弹出Form2 Form2 form2 = new Form2(); form2.ShowDialoag(); ②Form2中 ...

  9. JavaScript异步调用的发展历程

    同步与异步 通常,代码是由上而下依次执行的.如果有多个任务,就必须排队,前一个任务完成,后一个任务才能执行.这种连续的执行模式就叫做同步. a(); b(); c(); 复制代码 上面代码中,a.b. ...

最新文章

  1. strcpy.strcmp.strlen.strcat函数的实现
  2. 使用python库matplotlib绘制不同的图表
  3. 【Stimulsoft Reports Flex教程】从代码渲染报表
  4. Django的静态文件路径设置对比
  5. qt 实现html 编辑器,基于QT的HTML编辑器的设计与实现.doc
  6. windows端口备忘
  7. Java基础---接口是啥?
  8. C++STL笔记(一):STL综述
  9. 【QT】无需写connect代码关联信号和槽函数
  10. 创建连接数据库(DBLink)
  11. 数据挖掘关联规则挖掘之FpGrowth算法
  12. 视频教程-初级学习ArcGIS Engine视频课程-C#
  13. 【ManageEngine】如何利用好OpManager的报表功能
  14. SAP中英文转换--中文转英文
  15. 2.模仿小米通讯录的快速索引demo
  16. 智慧社区的现状分析及发展前景
  17. 解决UE4打包Android报错app:packageDebug FAILED的一个土方法
  18. 谈一下我是如何从使用json-lib到投入fastjson的怀抱....
  19. ZZNUOJ_C语言1046:奇数的乘积(完整代码)
  20. 史上最BT的真实案例集

热门文章

  1. TMS320F2837xD和TMS320F2837xS的区别
  2. react 输入框模糊搜索
  3. C# httppost 302 错误
  4. python 正则表达式筛选中文数字处理
  5. xxd命令中文参数说明
  6. 关于Django、Flask的一些面试知识点
  7. 记一次网站架构的搭建
  8. 中国内地首家美高梅品牌城市酒店在上海开业;奢华品牌洲至奢选首次进入大中华区;希尔顿花园酒店中国第50家开业...
  9. 市场调研报告-全球与中国皮肤护理服务市场现状及未来发展趋势
  10. matlab中冒号的作用