在日常的Java开发工作中,我们经常需要调用Dubbo接口.
Dubbo提供了通过invoke调用的方式,接下来由浅入深讲解不同的入参该如何传递.

首先使用telnet方式连接,连接成功之后,才可以使用invoke调用方法.

ls命令可以检验是否存在提供者以及方法.

dubbo中invoke多种调用入参方式_java

 

场景一

// 入参是一个简单的字符串
public String query(String address);

// 调用
invoke QueryUserInfoFacade.query("浙江省杭州市余杭区")

场景二

// 入参是一个字符串和整型
public String query(String address, Integer year);

// 调用
invoke QueryUserInfoFacade.query("浙江省杭州市余杭区", 2020)

场景三

public String query(UserInfoCondition condition);
public class UserInfoCondition {
private String address;
private String year;
}

// 调用
invoke QueryUserInfoFacade.query({"address":"浙江省杭州市余杭区","year":2020})
{
"address":"浙江省杭州市余杭区",
"year":2020
}

如果入参是一个对象,那么就使用一个花括号{}表示这个对象,对象里面的属性和属性值使用键值对key-value表示,key表示对象的属性,value表示属性的值

场景四

public String query(UserInfoCondition condition);
public class UserInfoCondition {
// 对象的属性是一个List
private List<String> addressList;
}

// 调用
invoke QueryUserInfoFacade.query({"addressList":["浙江省杭州市余杭区","四川省成都市"]})

既然接收的是一个对象condition,那么首先使用{}表示,属性使用键值对key-value表示. 对象里面有个List属性,相当于是数组,使用中括号[]表示,最后表示就是{“addressList”:[“浙江省杭州市余杭区”,“四川省成都市”]}.

{
"addressList":[
"浙江省杭州市余杭区",
"四川省成都市"
]
}

场景五

public String query(UserInfoCondition condition);
public class UserInfoCondition {
private List<UserInfo> userList;
}
public class UserInfo {
private String address;
private Integer year;
}

// 调用
invoke QueryUserInfoFacade.query({"userList":[{"address":"江苏","year":2019},{"address":"北京","year":2020}]})

根据前面的总结,我们知道列表使用数组表示,即中括号[ ].只是这次列表中不是简单的类型,而是一个对象,对象使用中括号表示.

{
"userList":[
{
"address":"江苏",
"year":2019
},
{
"address":"北京",
"year":2020
}
]
}

场景六

public String query(UserInfoCondition condition);
public class UserInfoCondition {
// List中是一个Map
private List<Map<String, Integer>> mList;
}

// 调用
invoke QueryUserInfoFacade.query({"mList":[{"李白":29},{"王维":30}]})

dubbo中invoke多种调用入参方式_java_02

{
"mList":[
{
"李白":29
},
{
"王维":30
}
]
}

1.列表依然是使用数组表示.
2.将Map<String, Integer>看作是一个对象.

场景七

public String query(UserInfoCondition condition);
public class UserInfoCondition {
// Map的键是一个字符串类型,值是一个对象类型
private List<Map<String, UserInfo>> mUserList;
}
public class UserInfo {
private String address;
private Integer year;
}

// 调用
invoke QueryUserInfoFacade.query({"mUserList":[{"作者一":{"address":"四川","year":2010}},{"作者二":{"address":"陕西","year":2030}}]})
{
"mUserList":[
{
"作者一":{
"address":"四川",
"year":2010
}
},
{
"作者二":{
"address":"陕西",
"year":2030
}
}
]
}

场景八

public String query(UserInfoCondition condition);
public class UserInfoCondition {
// Map的key不再是字符串类型,而是Integer类型
private List<Map<Integer, UserInfo>> mUserList;
}

如果按照上面场景七分析的方式传参会报错.我给Dubbo官方提了这个bug,官方也给了​​回复以及修复.​

实际的传参应该是

// 调用
invoke QueryUserInfoFacade.query({"mUserList":[{1:{"address":"HANGZHOU","year":"2020"},"class":"java.util.HashMap"},{2:{"address":"ZHEJIANG","year":"2021"},"class":"java.util.HashMap"}]})

invoke QueryUserInfoFacade.query({"mUserList":[{"1":{"address":"HANGZHOU","year":"2020"},"class":"java.util.HashMap"},{"2":{"address":"ZHEJIANG","year":"2021"},"class":"java.util.HashMap"}]})
{
"mUserList":[
{
"1":{
"address":"HANGZHOU",
"year":"2020"
},
"class":"java.util.HashMap"
},
{
"2":{
"address":"ZHEJIANG",
"year":"2021"
},
"class":"java.util.HashMap"
}
]
}

场景九

String query(Set<Integer> years);

// 调用
invoke QueryUserInfoFacade.query([1,2,3])
String query(Integer year, Set<String> months);

// 调用
invoke QueryUserInfoFacade.query(2020,["1","3","5"])
public String query(UserInfo userInfo);
public class UserInfo {
private Set<Integer> years
}

// 调用
invoke QueryUserInfoFacade.query({"years":[2010,2015,2020]})

和List类似,将Set也看作是数组即可.

场景十 内部类场景

public String query(UserInfo userInfo);

package com.xyz.service;
public class UserCondition {
public class UserInfo {
private String address;
private Integer year;
}
}


// 调用
invoke QueryUserInfoFacade.query({"class":"com.xyz.service.UserCondition$UserInfo","address":"浙江","year": 2020})

内部类使用$符号

{
"class":"com.xyz.service.UserCondition$UserInfo",
"address":"浙江",
"year":2020
}

场景十一 入参是枚举

public String query(Color color);
public enum Color {
BLUE(2),
RED(5);
private Integer value;
Color(Integer value) {
this.value = value;
}
}


// 调用
invoke QueryUserInfoFacade.query({"class":"com.infuq.condition.Color","name":"RED"})
{
"class":"com.infuq.condition.Color",
"name":"RED"
}
String query(UserInfo userInfo);
public class UserInfo {
private String year;
private String address;
private Color color;
}

// 调用
invoke QueryUserInfoFacade.query({"class":"com.infuq.condition.UserInfo","color":{"name":"BLUE"}})
{
"class":"com.infuq.condition.UserInfo",
"color":{
"name":"BLUE"
}
}

全文总结

1.对象使用{ }表示
2.List/Set使用[ ]表示
3.Map使用{ }表示
4.内部类使用$符号
5.枚举类使用name
6.在使用{ }的时候最好指定"class".

在平时工作中,我会使用python的方式调用invoke,代码如下

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import socket
import telnetlib
import sys


class DubboTelnet(object):

def __init__(self, host, port):
self.host = host
self.port = port
self.__connect_timeout = 10
self.__read_timeout = 10
self.__encoding = 'UTF-8'
self.__finish = 'dubbo>'

def invoke(self, command):
try:
telnet = telnetlib.Telnet(host=self.host, port=self.port, timeout=self.__connect_timeout)
except socket.error as err:
print("[host:%s port:%s] %s" % (self.host, self.port, err))
return

# 触发Dubbo提示符
telnet.write(b'\n')
# 执行命令
telnet.read_until(self.__finish.encode(), timeout=self.__read_timeout)
telnet.write(command.encode() + b"\n")
# 获取结果
data = ''
while str(data).find(self.__finish) == -1:
data = telnet.read_very_eager()
data = data.decode().split("\n")[0]
telnet.close()
return data


def main(host='127.0.0.1', port=20880):

conn = DubboTelnet(host, port)

cmd = 'invoke QueryUserInfoFacade.query({"class":"com.infuq.condition.UserInfo","color":{"name":"BLUE"}})'

ret = conn.invoke(cmd)
print(ret)

if __name__ == "__main__":
try:
main('127.0.0.1', 20880)
finally:
sys.exit()