在日常的Java开发工作中,我们经常需要调用Dubbo接口.
Dubbo提供了通过invoke调用的方式,接下来由浅入深讲解不同的入参该如何传递.
首先使用telnet方式连接,连接成功之后,才可以使用invoke调用方法.
ls命令可以检验是否存在提供者以及方法.
场景一
// 入参是一个简单的字符串
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}]})
{
"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()