关闭

dubbo学习六--泛化,回声测试,上下文信息,隐式传参,异步调用,本地调用

1813人阅读 评论(0) 收藏 举报
分类:

泛化引用

<dubbo:reference id="barService" interface="com.foo.BarService" generic="true" />

 

GenericService barService = (GenericService) applicationContext.getBean("barService");

Object result = barService.$invoke("sayHello", new String[] { "java.lang.String" }, new Object[] { "World" });

import com.alibaba.dubbo.rpc.service.GenericService;

...

 

// 引用远程服务

ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();

 // 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存

reference.setInterface("com.xxx.XxxService"); // 弱类型接口名

reference.setVersion("1.0.0");

reference.setGeneric(true); // 声明为泛化接口

 

GenericService genericService = reference.get(); // 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用

 

// 基本类型以及Date,List,Map等不需要转换,直接调用

Object result = genericService.$invoke("sayHello", new String[] {"java.lang.String"}, new Object[] {"world"});

 

// 用Map表示POJO参数,如果返回值为POJO也将自动转成Map

Map<String, Object> person = new HashMap<String, Object>();

person.put("name", "xxx");

person.put("password", "yyy");

Object result = genericService.$invoke("findPerson", new String[]{"com.xxx.Person"}, new Object[]{person});

// 如果返回POJO将自动转成Map

 

...

假设存在POJO如:

package com.xxx;

public class PersonImpl implements Person {

private String name;

private String password;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password= password;

}

}

则POJO数据:

Person person = new PersonImpl();

person.setName("xxx");

person.setPassword("yyy");

可用下面Map表示:

Map<String, Object> map = new HashMap<String, Object>();

map.put("class", "com.xxx.PersonImpl"); // 注意:如果参数类型是接口,或者List等丢失泛型,可通过class属性指定类型。

map.put("name", "xxx");

map.put("password", "yyy");



泛化实现

<bean id="genericService" class="com.foo.MyGenericService" />

<dubbo:service interface="com.foo.BarService" ref="genericService" />

 

package com.foo;

public class MyGenericService implements GenericService {

 

    public Object $invoke(String methodName, String[] parameterTypes, Object[] args) throws GenericException {

        if ("sayHello".equals(methodName)) {

            return "Welcome " + args[0];

        }

    }

 

}

...

GenericService xxxService = new XxxGenericService(); // 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口实现

 

ServiceConfig<GenericService> service = new ServiceConfig<GenericService>();

// 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存

service.setInterface("com.xxx.XxxService"); // 弱类型接口名

service.setVersion("1.0.0");

service.setRef(xxxService); // 指向一个通用服务实现

 

// 暴露及注册服务

service.export();


回声测试

回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。所有服务自动实现EchoService接口,只需将任意服务引强制转型为EchoService,即可使用。


<dubbo:reference id="memberService" interface="com.xxx.MemberService" />
MemberService memberService = ctx.getBean("memberService"); // 远程服务引用
 
EchoService echoService = (EchoService) memberService; // 强制转型为EchoService
 
String status = echoService.$echo("OK"); // 回声测试可用性
 
assert(status.equals("OK"))


上下文信息

RpcContext是一个ThreadLocal的临时状态记录器,当接收到RPC请求,或发起RPC请求时,RpcContext的状态都会变化。比如A调用B,B再调用C,则B机器上,在B调用C之前,RpcContext记录的是A调用B的信息,在B调用C之后,RpcContext记录的是B调用C。


(1)服务消费方

xxxService.xxx(); // 远程调用

boolean isConsumerSide = RpcContext.getContext().isConsumerSide(); // 本端是否为消费端,这里会返回true

String serverIP = RpcContext.getContext().getRemoteHost(); // 获取最后一次调用的提供方IP地址

String application = RpcContext.getContext().getUrl().getParameter("application");

// 获取当前服务配置信息,所有配置信息都将转换为URL的参数

// ...

yyyService.yyy(); // 注意:每发起RPC调用,上下文状态会变化

// ...





(2)服务提供方

public class XxxServiceImpl implements XxxService {

 

    public void xxx(){ // 服务方法实现

        boolean isProviderSide =RpcContext.getContext().isProviderSide(); // 本端是否为提供端,这里会返回true

        StringclientIP = RpcContext.getContext().getRemoteHost(); // 获取调用方IP地址

        Stringapplication =RpcContext.getContext().getUrl().getParameter("application");

// 获取当前服务配置信息,所有配置信息都将转换为URL的参数

        //...

        yyyService.yyy();// 注意:每发起RPC调用,上下文状态会变化

        boolean isProviderSide = RpcContext.getContext().isProviderSide();// 此时本端变成消费端,这里会返回false

        //...

    }

 

}



隐式传参

注意path, group, version, dubbo, token, timeout几个key有特殊处理,请使用其它key值。



(1)服务消费方

RpcContext.getContext().setAttachment("index", "1");

 // 隐式传参,后面的远程调用都会隐式将这些参数发送到服务器端,类似cookie,用于框架集成,不建议常规业务使用

xxxService.xxx(); // 远程调用

// ...

【注】 setAttachment设置的KV,在完成下面一次远程调用会被清空。即多次远程调用要多次设置。

(2)服务提供方

public class XxxServiceImpl implements XxxService {

 

    public void xxx(){ // 服务方法实现

        Stringindex = RpcContext.getContext().getAttachment("index");

// 获取客户端隐式传入的参数,用于框架集成,不建议常规业务使用

        //...

    }

 

}


consumer.xml

<dubbo:reference id="fooService" interface="com.alibaba.foo.FooService">

      <dubbo:method name="findFoo" async="true" />

</dubbo:reference>

<dubbo:reference id="barService" interface="com.alibaba.bar.BarService">

      <dubbo:method name="findBar" async="true" />

</dubbo:reference>

调用代码:

fooService.findFoo(fooId); // 此调用会立即返回null

Future<Foo> fooFuture = RpcContext.getContext().getFuture();

// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future。

 

barService.findBar(barId); // 此调用会立即返回null

Future<Bar> barFuture = RpcContext.getContext().getFuture();

 // 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future。

 

// 此时findFoo和findBar的请求同时在执行,客户端不需要启动多线程来支持并行,而是借助NIO的非阻塞完成。

 

Foo foo = fooFuture.get(); // 如果foo已返回,直接拿到返回值,否则线程wait住,等待foo返回后,线程会被notify唤醒。

Bar bar = barFuture.get(); // 同理等待bar返回。

 

// 如果foo需要5秒返回,bar需要6秒返回,实际只需等6秒,即可获取到foo和bar,进行接下来的处理。

你也可以设置是否等待消息发出:(异步总是不等待返回)

  • sent="true" 等待消息发出,消息发送失败将抛出异常。
  • sent="false" 不等待消息发出,将消息放入IO队列,即刻返回。

<dubbo:method name="findFoo" async="true" sent="true" />

如果你只是想异步,完全忽略返回值,可以配置return="false",以减少Future对象的创建和管理成本:

<dubbo:method name="findFoo" async="true" return="false" />



本地调用

本地调用 ,使用了Injvm协议,是一个伪协议,它不开启端口,不发起远程调用,只在JVM内直接关联,但执行dubbo的Filter链。


Define injvm protocol:

<dubbo:protocol name="injvm" />

Set default protocol:

<dubbo:provider protocol="injvm" />

Set service protocol:

<dubbo:service protocol="injvm" />

Use injvm first:

<dubbo:consumer injvm="true" .../>

<dubbo:provider injvm="true" .../>

<dubbo:reference injvm="true" .../>

<dubbo:service injvm="true" .../>

注意:服务暴露与服务引用都需要声明injvm="true"

 

自动暴露、引用本地服务

从 dubbo 2.2.0 开始,每个服务默认都会在本地暴露;在引用服务的时候,默认优先引用本地服务;如果希望引用远程服务可以使用一下配置强制引用远程服务。

...

    <dubbo:reference ... scope="remote" />

...





1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:428577次
    • 积分:8042
    • 等级:
    • 排名:第2833名
    • 原创:222篇
    • 转载:827篇
    • 译文:16篇
    • 评论:25条
    最新评论