Dobbo设置说明
一般情况下,每个值都应该指定一class 字段显式指定该值的Java类型,如果Java类型跟值类型不匹配,会自动进行类型转换。
尽管string不属于基本类型,但是作为Avro的基本类型,故而也将Java String对象的处理归于基本类型中一并处理。
一、Flow 设置
由于是通过解析输入Flow的每条数据(Record)来获得Dubbo调用方法的参数值,所以,需要严格定义输入Flow的Schema,如果输入是通过Avro schema方式定义,则在针对class 字段的设置,可利用Avro Schema的default字段特性进行默认值指定。
1.1 Java基本类型
针对每个值指定class字段,显式指出其Java类型。
方法:
call(int arg1, long arg2, float arg3, double arg4, boolean arg5, String arg6, byte arg7)
Avro Schema设置int参数片段:
{
"namespace": "com.baishancloud", "name": "primitive_class",
"type": "record",
"fields": [ {"name": "arg1",
"type": {
"name": "arg1",
"type": "record",
"fields": [
{"name": "class","type": "string","default": "int" },
{"name": "arg1","type": "int"}
]
}}]
}
说明:
field名字为arg1,对应第一个参数,名字可以任意,并且两field以及record名字必须一致,且顺序必须保证跟Dubbo调用参数对应。
由于需要记录参数值相对应的class字段来指定Java类名,同时也可指定class的默认值,因此需定义一record类型来记录两个字段class(类型一定是string)和同名的arg1来记录值(类型是Avro支持的类型)。
Record的JSON数据:
{
"arg1": {"class": "int","arg1": 11},
"arg2": {"class": "long","arg2": 1111},
"arg3": {"class": "float","arg3": 1.11},
"arg4": {"class": "double","arg4": 1.1111},
"arg5": {"class": "boolean","arg5": true},
"arg6": {"class": "java.lang.String","arg6": "test"},
"arg7": {"class": "byte","arg7": "\u0041"}
}
1.2 默认类型
由于采用Avro Schema和通用Record来存储Dubbo所需参数值序列,故而基本类型可默认支持int, long, float, double, boolean, String, byte,6种基本类型和Sting对象。
再者,Avro类型少于Java的基本类型,因此诸如char,short无法采用默认类型匹配,必须显式指定值的类名,即必须提供class字段。
方法:
call(int arg1, long arg2, float arg3, double arg4, boolean arg5, String arg6, byte arg7)
Avro Schema设置:
{
"namespace": "com.baishancloud", "name": "primitive",
"type": "record",
"fields": [ {"name": "arg1","type": "int"},
{"name": "arg2","type": "long"},
{"name": "arg3","type": "float"},
{"name": "arg4","type": "double"},
{"name": "arg5","type": "boolean"},
{"name": "arg6","type": "string"},
{"name": "arg7","type": "bytes"} ]
}
Record的JSON数据:
{
"arg1": 11,
"arg2": 1111,
"arg3": 1.11,
"arg4": 1.1111,
"arg5": true,
"arg6": "test",
"arg7": "\u0041"
}
1.3 基本类型对象
方法:
call(Character arg1, Byte arg2, Short arg3, Integer arg4, Long arg5, Float arg6, Double arg7, Boolean arg8, String arg9)
Avro Schema设置Character参数片段:
{
"namespace": "com.baishancloud", "name": "primitive_object",
"type": "record",
"fields": [{
"name": "arg1",
"type": {
"name": "arg1",
"type": "record",
"fields": [
{"name": "class","type": "string","default": "java.lang.Character"},
{"name": "arg1","type": "string"}
]
}
}]
}
说明:
在Avro中可为class设置默认值。Avro Schema同显式指定class的基本类型雷同(1.1) Record的JSON数据:
{
"arg1": {"class": "java.lang.Character","arg1": "X"},
"arg2": {"class": "java.lang.Byte","arg2": "\u0041"},
"arg3": {"class": "java.lang.Short","arg3": 123},
"arg4": {"class": "java.lang.Integer","arg4": 1234},
"arg5": {"class": "java.lang.Long","arg5": 12345},
"arg6": {"class": "java.lang.Float","arg6": 1.11},
"arg7": {"class": "java.lang.Double","arg7": 1.1111},
"arg8": {"class": "java.lang.Boolean","arg8": true},
"arg9": {"class": "java.lang.String","arg9": "ABC"}
}
说明:
两field名字都为arg1,record名字也需要相同, 即三者需要统一。
class是Character,而Avro Type是String,由于类型不同,会在解析过程中自动进行类型转换,比如此参数。
对于Character,如果Record值超过一个字符,将只会取第一个字符,丢弃其他字符,因为Character只能容纳一个字符。
同样,对于Boolean,如果值不是true/false,则解析后,一概为false。
1.4 基本类型Array
方法:
call(byte[] arg1, int[] arg2, long[] arg3, float[] arg4, double[] arg5, boolean[] arg6, String[] arg7)
Avro Schema设置byte[]参数片段:
{
"namespace": "com.baishancloud",
"type": "record",
"name": "primitive_array",
"fields": [
{
"name": "arg1",
"type": {"type": "array","items": "bytes"}
}
]
}
Record的JSON数据:
{
"arg1": ["\u0041","\u0042","\u0043"],
"arg2": [1,2,3],
"arg3": [9,8,7],
"arg4": [1.1,2.2,3.3],
"arg5": [9.9,8.8,7.7],
"arg6": [true,false,true],
"arg7": ["A","B","C"]
}
1.5 基本类型对象Array
方法:
call(Character[] arg1, Byte[] arg2, Short[] arg3, Integer[] arg4, Long[] arg5, Float[] arg6, Double[] arg7, Boolean[] arg8, String[] arg9)
Avro Schema设置Character[]参数片段:
{
"namespace": "com.baishancloud", "name": "primitive_object_array",
"type": "record",
"fields": [ {
"name": "arg1",
"type": { "name": "arg1", "type": "record",
"fields": [ {"name": "class","type": "string"},
{"name": "arg1",
"type": {
"type": "array",
"items": {
"name": "arg1_elem", "type": "record",
"fields": [
{"name": "class","type": "string",
"default": "java.lang.Character"},
{"name": "arg1","type": "string"}
]
}
}
}]
}
} ]
}
说明:
第一个class是指明数组的类名。第二个class指定数组对象的类名
Record的JSON数据Charactor[]片段:
{
"arg1": {
"class": "[Ljava.lang.Character;",
"arg1": [
{"class": "java.lang.Character","arg1": "A"},
{"class": "java.lang.Character","arg1": "B"},
{"class": "java.lang.Character","arg1": "C"}
]
}
}
1.6 基本类型对象List
方法:
call(List<Character> arg1, List<Byte> arg2, List<Short> arg3, List<Integer> arg4)
Avro Schema设置
跟基本类型对象Array的Avro Schema设置一样,只是体现在class值的不同。
Record的JSON数据:
{
"arg1": {
"class": "java.lang.List",
"arg1": [
{"class": "java.lang.Character","arg1": "A"},
{"class": "java.lang.Character","arg1": "B"},
{"class": "java.lang.Character","arg1": "C"}
]
}
}
说明: 第一级class为List。
1.7 基本类型对象Map
方法:
call(Map<String,Boolean> arg1, Map<Float,Boolean> arg2)
Avro Schema设置片段:
{
"namespace": "com.baishancloud", "name": "primitive_object_map",
"type": "record",
"fields": [{
"name": "arg1",
"type": {
"name": "arg1", "type": "record",
"fields": [{"name": "class", "type": "string", "default": "java.lang.Map"},
{"name": "arg1",
"type": { "type": "array",
"items": {
"name": "arg1_elem", "type": "record",
"fields": [{"name": "key",
"type": {
"name": "arg1_key", "type": "record",
"fields": [{
"name": "class", "type": "string",
"default": "java.lang.String"},
{"name": "arg1","type": "string"}]
}},
{ "name": "value",
"type": {
"name": "arg1_value", "type": "record",
"fields": [{
"name": "class", "type": "string"
"default": "java.lang.Boolean"},
{"name": "arg1","type": "boolean"}]
}
}]
}
}
}]
}
}]
}
Record的JSON数据:
{
"arg1": {
"class": "java.util.Map",
"arg1": [
{
"key": {"class": "java.lang.String","arg1": "A"},
"value": {"class": "java.lang.Boolean","arg1": true}
},
{
"key": {"class": "java.lang.String","arg1": "B"},
"value": {"class": "java.lang.Boolean","arg1": false}
},
{
"key": {"class": "java.lang.String","arg1": "C"},
"value": {"class": "java.lang.Boolean","arg1": true}
}
]
}
}
1.8 POJO对象
方法:
call(Person person)
Avro Schema设置片段:
{
"namespace": "com.baishancloud", "name": "pojo", "type": "record",
"fields": [{"name": "person",
"type": {
"name": "person", "type": "record",
"fields": [
{"name": "class","type": "string","default": "x.y.Person"},
{"name": "id","type": "int"},
{"name": "name","type": "string"},
{"name": "age","type": "int"}
]
}
}]
}
说明:
其中person 的Avro record为POJO对象定义,除class字段指定该POJO的类名,其他字段均为该对象的成员变量。
Record的JSON数据:
{
"person": {
"class": "x.y.Person",
"id": 1,
"name": "Test",
"age": 26
}
}
1.9 POJO对象Array
方法:
call(Person[] persons)
Avro Schema设置片段:
{
"namespace": "com.baishancloud", "name": "pojo_array", "type": "record",
"fields": [{"name": "persons",
"type": {
"name": "persons", "type": "record",
"fields": [
{"name": "class", "type": "string", "default": "[Lx.y.Person;"},
{"name": "persons",
"type": { "type": "array",
"items": {
"name": "person", "type": "record",
"fields": [
{"name": "class","type": "string","default": "x.y.Person"},
{"name": "id","type": "int"},
{"name": "name","type": "string"},
{"name": "age","type": "int"}
]
}}
}]
}
} ]
}
Record的JSON数据:
{
"persons": {
"class": "[Lx.y.Person;",
"persons": [
{"class": "x.y.Person","id": 1,"name": "Zhang","age": 28},
{"class": "x.y.Person","id": 2,"name": "Wang","age": 26},
{"class": "x.y.Person","id": 3,"name": "Li","age": 22}
]
}
}
1.10 POJO对象List
方法:
call(List<Person>)
Avro Schema设置
跟POJO对象Array的Avro Schema定义类似,只是第一级的class字段是List。
Record的JSON数据:
{
"persons": {
"class": "java.lang.List",
"persons": [
{"class": "x.y.Person","id": 1,"name": "Zhang","age": 28},
{"class": "x.y.Person","id": 2,"name": "Wang","age": 26},
{"class": "x.y.Person","id": 3,"name": "Li","age": 22}
]
}
}
1.11 POJO对象Map
方法:
call(Map<String, Person>)
Avro Schema设置片段:
同基本类型对象Map类似,只是value字段为一POJO的record定义。
Record的JSON数据:
同基本类型对象Map类似,只是value字段为一POJO的JSON序列化值。
二、Custom设置:
如果Dubbo调用方法的参数为一个,则设置的JSON,可以不为数组方式。
如果多个参数,则一定是JSON数组方式。
2.1 基本类型:
通过class字段指定该参数的Java类型,应与具体Java Class对应。
方法:
call(char arg1, byte arg2, short arg3, int arg4, long arg5, float arg6, double arg7, boolean arg8)
设置:
[
{"class": "char","value": "A"},
{"class": "byte","value": 66},
{"class": "short","value": 67},
{"class": "int","value": 68},
{"class": "long","value": 69},
{"class": "float","value": 1.1},
{"class": "double","value": 2.2},
{"class": "boolean","value": true}
]
说明:
class为基本类型名。
value对应的一个基本类型值。
2.2 默认类型支持:
即默认支持的参数类型,仅支持int,double,boolean,String三种基本类型和String对象,无需指定参数的class类型,但相应的参数为对象类型,比如Double,则必须明确指定class类型。
方法:
call(int arg1, double arg2, boolean arg3, String arg4)
设置:
{
"arg1": 11,
"arg2": 11.11,
"arg3": true,
"arg4": "test"
}
2.3 基本类型对象:
定义类似2.2 基本类型,提供class字段,但指定为Object class。
方法:
call(Character arg1, Byte arg2, Short arg3, Integer arg4, Long arg5, Float arg6, Double arg7, Boolean arg8, String arg9)
设置:
[
{"class": "java.lang.Character","value": "A"},
{"class": "java.lang.Byte","value": 66},
{"class": "java.lang.Short","value": 67},
{"class": "java.lang.Integer","value": 68},
{"class": "java.lang.Long","value": 69},
{"class": "java.lang.Float","value": 1.1},
{"class": "java.lang.Double","value": 2.2},
{"class": "java.lang.Boolean","value": true},
{"class": "java.lang.String","value": "test"}
]
说明:
class为基本类型对象类名。
value对应的一个基本类型值。
2.4 基本类型Array
经过测试,Dubbo不支持支付数组char[]类型,会在传输过程中序列化为字符串(其实字符串数组本来就是字符串!)。
方法:
call(byte[] arg1, short[] arg2, int[] arg3, long[] arg4, float[] arg5, double[] arg6, boolean[] arg7)
设置:
[
{"class": "[B","value": [ 65, 66, 67]},
{"class": "[S","value": [ 65, 66, 67]},
{"class": "[I","value": [ 65, 66, 67]},
{"class": "[J","value": [ 65, 66, 67]},
{"class": "[F","value": [ 1.1,2.2,3.3]},
{"class": "[D","value": [ 1.1,2.2,3.3]},
{"class": "[Z","value": [ true,false,true]}
]
说明:
class为基本类型数组类名,即“[”+基本类型数组类特殊字符。
value对应的一个基本类型值的数组。
2.5 基本类型对象Array
方法:
call(Character[] arg1, Byte[] arg2, Short[] arg3, Integer[] arg4, Long[] arg5, Float[] arg6, Double[] arg7, Boolean[] arg8, String[] arg9)
设置:
[
{"class": "[Ljava.lang.Character;","value": ["A","B","C"]},
{"class": "[Ljava.lang.Byte;","value": [65,66,67]},
{"class": "[Ljava.lang.Short;","value": [65,66,67]},
{"class": "[Ljava.lang.Integer;","value": [65,66,67]},
{"class": "[Ljava.lang.Long;","value": [65,66,67]},
{"class": "[Ljava.lang.Float;","value": [1.1,2.2,3.3]},
{"class": "[Ljava.lang.Double;","value": [1.1,2.2,3.3]},
{"class": "[Ljava.lang.Boolean;","value": [true,false,true]},
{"class": "[Ljava.lang.String;","value": ["A","B","C"]}
]
当然也可以对每个值进行类型限定,比如对于Character[]数组:
{
"class": "[Ljava.lang.Character;",
"value": [
{"class": "java.lang.Character","value": "A"},
{"class": "java.lang.Character","value": "B"},
{"class": "java.lang.Character","value": "C"},
]
}
说明:
第一级的class为相应数组类名,即“[L”+对象类名+“;”。
第一级的value对应的一个数组,每个数组同时指定相应的class字段,显式指出值的类型。
2.6 基本类型对象List
方法:
call(List<Character> arg1, List<Byte> arg2, List<Short> arg3, List<Integer> arg4, List<Long> arg5, List<Float> arg6, List<Double> arg7, List<Boolean> arg8, List<String> arg9)
设置:
[
{"class": "java.util.List", "value": [
{"class": "java.lang.Character","value": "A"},
{"class": "java.lang.Character","value": "B"} ]
},
{"class": "java.util.List", "value": [
{"class": "java.lang.Byte","value": 65},
{"class": "java.lang.Byte","value": 66} ]
},
{"class": "java.util.List", "value": [
{"class": "java.lang.Short","value": 65},
{"class": "java.lang.Short","value": 66}]
},
{"class": "java.util.List", "value": [
{"class": "java.lang.Integer","value": 65},
{"class": "java.lang.Integer","value": 66}]
},
{"class": "java.util.List", "value": [
{"class": "java.lang.Long","value": 65},
{"class": "java.lang.Long","value": 66} ]
},
{"class": "java.util.List", "value": [
{"class": "java.lang.Float","value": 1.1},
{"class": "java.lang.Float","value": 2.2} ]
},
{"class": "java.util.List", "value": [
{"class": "java.lang.Double","value": 1.1},
{"class": "java.lang.Double","value": 2.2}]
},
{"class": "java.util.List", "value": [
{"class": "java.lang.Boolean","value": true},
{"class": "java.lang.Boolean","value": false}]
},
{"class": "java.util.List","value": [
{"class": "java.lang.String","value": "A"},
{"class": "java.lang.String","value": "B"}]
}
]
说明:
第一级的class为List类名,即便是泛型,也无需指定泛型类名。
第一级的value对应的一个数组,同对象数组,每个数组同时指定相应的class字段,显式指出值的类型。
2.7 基本类型对象Map
对于Map类型,建议key尽量为String类型,因为如果key为其他类型,可能在传输序列化过程中出现问题。
方法:
call(Map<Short, Character> arg1, Map<Long, Byte> arg2, Map<Double, Boolean> arg3)
设置:
[
{
"class": "java.util.Map",
"value": [{
"key": {"class": "java.lang.Short","value": 1},
"value": {"class": "java.lang.Character","value": "A"}
},
{
"key": {"class": "java.lang.Short","value": 2},
"value": {"class": "java.lang.Character","value": "B"}
}]
},
{
"class": "java.util.Map",
"value": [{
"key": {"class": "java.lang.Long","value": 1},
"value": {"class": "java.lang.Byte","value": 65}
},
{
"key": {"class": "java.lang.Long","value": 2},
"value": {"class": "java.lang.Byte","value": 66}
}]
},
{
"class": "java.util.Map",
"value": [{
"key": {"class": "java.lang.Double","value": 1},
"value": {"class": "java.lang.Boolean","value": true}
},
{
"key": {"class": "java.lang.Double","value": 2},
"value": {"class": "java.lang.Boolean","value": false}
}]
}
]
说明:
第一级的class为Map类名,即便是泛型,也无需指定泛型类名 。 第一级的value对应的一个数组,每个数组通过key/value来分别限定参数对象的key/value对象,并指定相应的class字段,显式指出值的类型。
如果key为String类型,可简单采用如下定义比如Map<String, Short>:
{
"class": "java.util.Map",
"value": {
"mykey1": {"class": "java.lang.Short","value": 11},
"mykey2": {"class": "java.lang.Short","value": 22}
}
}
2.8 POJO对象
由于Dubbo会将POJO对象自动序列化为Map对象,成员变量与值即为key/value对,也会额外添加一class字段记录该POJO的class名字。
方法:
valid(Person person)
设置:
{
"class": "x.y.Person",
"value": {"class": "x.y.Person","id": 123,"name": "Test","age": 20}
}
说明:
第一级的class为标注该类的名字
第一级的value对应的就是POJO 对象JSON化后的值
2.9 POJO对象Array
方法:
filter(Person[] persons)
设置:
{
"class": "[Lx.y.Person;",
"value": [
{"class": "x.y.Person","id": 123,"name": "Test","age": 20},
{"class": "x.y.Person","id": 124,"name": "Mock","age": 28}
]
}
说明:
第一级的class为POJO数组的类名,即“[L”+POJO类名+“;”。
第一级的value同POJO List对象,也是对应多POJO 对象JSON化后的值的数组列表。
2.10 POJO对象List
方法:
filter(List<Person> persons)
设置:
{
"class": "java.util.List",
"value": [
{"class": "x.y.Person","id": 123,"name": "Test","age": 20},
{"class": "x.y.Person","id": 124,"name": "Mock","age": 28}
]
}
说明:
第一级的class为List类名,尽管是泛型,也无需指定泛型的POJO类名
第一级的value对应多POJO 对象JSON化后的值的数组列表。
2.11 POJO对象Map
方法:
convert(Map<String, Person> persons)
设置:
{
"class": "java.util.Map",
"value": {
"master1": {"class": "x.y.Person","id": 123,"name": "Test","age": 20},
"master2": {"class": "x.y.Person","id": 124,"name": "Mock","age": 28}
}
}
说明:
第一级的class为Map类名,同List,尽管是泛型,也无需指定泛型类。
第一级的value为一Map,该Map的key即为Map的key字符串值,该Map的value为POJO 对象JSON化后的值。
三、问题
可能仍旧存在如下问题:
不支持char[]参数的Dubbo调用,应该是由于Dubbo传输的序列化,将char[]序列化成了字符串。
Map的key为任意对象,可能目前还不完全支持良好,建议key只支持String类型。
POJO的深层嵌套对象(子对象),目前可能受Dubbo以及JSON序列化和Avro Schema定义复杂度的急剧增加,不建议支持2层以上的嵌套。
Flow跟Custom的设置行为不一样,因为受制于两套系统,Flow基于Avro Schema的Record系统,而Custom基于是Jackson对象的解析加载机制。
由于Dubbo本身的限制,如果是POJO,目前不支持内部类,即类名中带$的类。