目录
- 1、模拟等待
- 2、服务端接口实现
- 3、消费者端接口调用
- 4、测试
- 5、注意
- 6、特殊说明
官方说明 Dubbo不只提供了堵塞式的的同步调用,同时提供了异步调用的方式。
这种方式主要应用于提供者接口响应耗时明显,消费者端可以利用调用接口的时间去做一些其他的接口调用,利用 Future 模式来异步等待和获取结果即可。
这种方式可以大大的提升消费者端的利用率。 目前这种方式可以通过XML的方式进行引入。
由于注解模式下不支持方法级别的method属性设置,所以这个demo测试,使用xml模式
1、模拟等待
为了模拟等待,通过 int timeMills参数,标明需要休眠多少毫秒后才会进行返回。
public interface HelloService {
String sayHello(String name, int timeMills);
}
2、服务端接口实现
让线程等待一段时间
package com.lagou.service.impl;
import com.lagou.service.HelloService;
public class HelloServiceImpl implements HelloService {
public String sayHello(String name, int timeMills) {
try {
Thread.sleep(timeMills);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "【我是服务端】hello1111:" + name;
}
}
其他配置详见基本案例(XML版) dubbo-provider.xml
ProviderApplication.java
3、消费者端接口调用
配置异步调用
<dubbo:method name="sayHello" async="true"/>
完整如下:
<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="service-consumer" >
<dubbo:parameter key="qos.enable" value="true" ></dubbo:parameter>
<dubbo:parameter key="qos.port" value="33333"></dubbo:parameter>
<!-- value为true:talnet用ip登录之后可以操作,否则只能登录不能操作-->
<dubbo:parameter key="qos.accept.foreign.ip" value="true" ></dubbo:parameter>
</dubbo:application>
<!-- 使用zookeeper注册中心暴露发现服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="helloService" interface="com.lagou.service.HelloService" >
<!-- 设置方法是否异步调用 :默认是false。
TODO 注意:方法在异步调用时的返回值是空,我们可以通过 RpcContext.getContext().getFuture()
获取Future对象,来进行后续的结果等操作
-->
<dubbo:method name="sayHello" async="true"/>
</dubbo:reference>
</beans>
4、测试
我们休眠100毫秒,然后再去进行获取结果。方法在同步调用时的返回值是空,我们可以通过 RpcContext.getContext().getFuture() 来进行获取Future对象来进行后续的结果等待操作。
package com.lagou;
import com.lagou.service.HelloService;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.concurrent.Future;
public class AsyncConsumerApplication {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:dubbo-consumer.xml");
System.out.println("Consumer 启动成功!");
HelloService helloService = (HelloService) context.getBean("helloService"); // 获取远程服务代理
System.out.println("获取接口成功!");
while (true) {
System.in.read();
String hello = helloService.sayHello("world", 100); // 执行远程方法
// 利用Future 模式来获取
Future<Object> future = RpcContext.getContext().getFuture();
System.out.println("result:" + hello); // 直接显示:结果为null
System.out.println("future===》result:" + future.get()); // 用future,结果可以争取获取到
}
}
}
测试结果如下:
5、注意
方法在异步调用时的返回值是空,我们可以通过 RpcContext.getContext().getFuture() 获取Future对象,来进行后续的结果等操作。详见第4步测试类中的具体代码
6、特殊说明
需要特别说明的是,该方式的使用,请确保dubbo的版本在2.5.4及以后的版本使用。 原因在于在2.5.3及之前的版本使用的时候,会出现异步状态传递问题。
比如我们的服务调用关系是 A -> B -> C , 这时候如果A向B发起了异步请求,在错误的版本时,B向C发起的请求也会连带的产生异步请求。这是因为在底层实现层面,他是通过 RPCContext 中的attachment 实现的。在A向B发起异步请求时,会在 attachment 中增加一个异步标示字段来表明异步等待结果。B在接受到A中的请求时,会通过该字段来判断是否是异步处理。但是由于值传递问题,B向C发起时同样会将该值进行传递,导致C误以为需要异步结果,导致返回空。这个问题在2.5.4及以后的版本进行了修正。