/sofa-hessian-go

Primary LanguageGoApache License 2.0Apache-2.0

目录

概要

sofa-hessian-gohessian 2.0/1.0 serialization protocol 的 Golang 实现,包括 1.0 协议以及 2.0 协议的 java3.xjava4.x 版本,同时还提供了 JSONhessian 类型系统互相转换的设计。

在此非常感谢 node-modules/hessian.js 提供的 golden files(测试数据), 两者底层复用了同样的测试数据集。

类型系统

hessian 的类型系统由 8 种基础类型和 3 种复合类型,以及 3 种 引用类型组成。

基础类型

  • binary
  • bool
  • string
  • int32
  • int64
  • float64
  • null
  • date (64bit)

复合类型

  • list
  • map
  • object

引用类型

  • class reference: represents the definition of class
  • type reference: represents the name of class
  • object reference: represents the instance of object or list or map.

编码规范

sofa-hessian-go 遵循以下编码规范,将 go 的类型转化为 hessian 的类型。

  • uint8/int8 => int32
  • uint16/int => int32
  • uint32/int32 => int32
  • uint64/int64 => int64
  • uint/int => int64
  • bool => bool
  • string => string
  • []byte => binary
  • nil => null
  • time.Time => date
  • map[interface{}]interface{} => map
  • []interface{} => list
  • struct => object

解码规范

sofa-hessian-go 遵循以下解码规范,将 hessian 的类型转化为 go 的类型。

  • int32 => int32

  • int64 => int64

  • bool => bool

  • string => string

  • null => nil

  • date => time.Time

  • map

    • untyped map => map[interface{}]interface{}
    • typed map => *JavaMap{class: "balaba", map[interface{}]interface{}}
  • list

    • untyped list => []interface{}
    • typed list => *JavaList{class: "balaba", []interface{}}
  • object =>

    • concrete object => go concrete struct
    • generic object => *JavaObject{class: "balaba", JavaObject{}}

json 转换

JSON 的类型系统比 HESSIAN 的类型系统更精简,从理论上是可以在一定人为约束条件下做到 JSON 和 HESSIAN 的类型转换。

JSON 到 HESSIAN 的类型转换

给定一个 HESSIAN 类型总是存在一种 JSON 类型可以等价描述出来。但是在实际实现中只有一种情况例外,即 HESSIAN 可以以较小的代价描述循环引用的数据结构,JSON 虽然可以描述,但通常导致的结果就是无限递归导致爆栈。 JSON 天然无法处理循环引用的数据结构,不过 sofa-hessian-go 在实际的实现中以较小的代价跟踪循环引用的问题,以不完整的数据结构代替了爆栈。

基础类型

NULL 类型

给定一个 hessian null 类型总是可以用 json null 类型描述即 json.null => hessian.bool

bool 类型

给定一个 hessian bool 类型总是可以用 json bool 类型描述即 json.bool => hessian.bool

int 类型

给定一个 hessian int 类型无法直接用 json number 类型描述,但是我们可以通过 json object 包装来表示即

json.object {
	"$class": "int", // or "java.lang.Integer"
	"$": number
} => hessian.int

long 类型

给定一个 hessian long 类型总是可以用 json number 类型描述即 json.number => hessian.long

double 类型

给定一个 hessian double 类型总是可以用 json object 类型描述即

json.object {
	"$class": "double", // or "java.lang.Double"
	"$": number
} => hessian.double

binary 类型

给定一个 hessian binary 类型总是可以用 json object 类型描述即

json.object {
	"$class": "bytes",
	"$": "base64 encoding string"
} => hessian.binary

date 类型

给定一个 hessian date 类型总是可以用 json object 类型描述即

json.object {
	"$class": "date", // or "java.util.Date"
	"$": number
} => hessian.date

复合类型

map 类型

给定一个 hessian map 类型总是可以用 json object 类型描述即 json.object => hessian.map

list 类型

给定一个 hessian map 类型总是可以用 json array 类型描述即 json.array => hessian.list

object 类型

给定一个 hessian object 类型总是可以用 json object 类型描述即

json.object {
	"$class": "classname",
	"$": json element
} => hessian.object

HESSIAN 到 JSON 的类型转换

给定一个 JSON 类型总是存在一种 HESSIAN 类型可以等价描述出来.

基础类型

number

给定一个 json number 类型总是可以用 hessian int/long/double 类型描述即 hessian.int|long/double => json.number

string

给定一个 json string 类型总是可以用 hessian string 类型描述即 hessian.string => json.string

bool

给定一个 json bool 类型总是可以用 hessian bool 类型描述即 hessian.bool => json.bool

null

给定一个 json null 类型总是可以用 hessian null 类型描述即 hessian.null => json.null

复合类型

object

给定一个 json object 类型总是可以用 hessian map 类型描述即 hessian.map => json.object

array

给定一个 json array 类型总是可以用 hessian array 类型描述即 hessian.array => json.array

附录

JSON 类型系统

json
    element

value
    object
    array
    string
    number
    "true"
    "false"
    "null"

HESSIAN 类型系统

#starting production
top        ::= value

#main production
value      ::= null
           ::= binary
           ::= boolean
           ::= class-def value
           ::= date
           ::= double
           ::= int
           ::= list
           ::= long
           ::= map
           ::= object
           ::= ref
           ::= string

API

encode

查看 examples/sofahessian_examples_test.go

decode

查看 examples/sofahessian_examples_test.go

json

查看 examples/sofahessian_examples_test.go

CLI

install

make hessian

decode

bin/hessian decode 4fbc636f6d2e616c697061792e736f66612e7270632e636f72652e726571756573742e536f666152657175657374950d7461726765744170704e616d650a6d6574686f644e616d651774617267657453657276696365556e697175654e616d650c7265717565737450726f70730d6d6574686f64417267536967736f904e0873617948656c6c6f1048656c6c6f536572766963653a312e304d0870726f746f636f6c04626f6c74117270635f74726163655f636f6e746578744d09736f6661527063496401300473616d700566616c73650b73797350656e4174747273000d736f666143616c6c6572496463000c736f666143616c6c65724970000b736f6661547261636549641e3061306665383633313537313034363337383735383130303138363232300c736f666150656e4174747273000e736f666143616c6c65725a6f6e65000d736f666143616c6c6572417070007a7a567400075b737472696e676e02106a6176612e6c616e672e537472696e67046c6f6e677a05776f726c64e1 --version=3

&hessian.JavaObject{
  class: "com.alipay.sofa.rpc.core.request.SofaRequest",
  names: []string{
    "targetAppName",
    "methodName",
    "targetServiceUniqueName",
    "requestProps",
    "methodArgSigs",
  },
  values: []interface {}{
    nil,
    "sayHello",
    "HelloService:1.0",
    map[interface {}]interface {}{
      "protocol":          "bolt",
      "rpc_trace_context": map[interface {}]interface {}{
        "sofaCallerZone": "",
        "sofaCallerApp":  "",
        "sofaRpcId":      "0",
        "sysPenAttrs":    "",
        "sofaCallerIdc":  "",
        "sofaPenAttrs":   "",
        "samp":           "false",
        "sofaCallerIp":   "",
        "sofaTraceId":    "0a0fe8631571046378758100186220",
      },
    },
    &hessian.JavaList{
      class: "[string",
      value: []interface {}{
        "java.lang.String",
        "long",
      },
    },
  },
}
"world"
1

fromjson

bin/hessian fromjson '{"$class": "com.alipay.sofa.rpc.core.request.SofaRequest", "$": {"1": "2"}}' --format hex

43302c636f6d2e616c697061792e736f66612e7270632e636f72652e726571756573742e536f666152657175657374910131600132

bin/hessian decode 43302c636f6d2e616c697061792e736f66612e7270632e636f72652e726571756573742e536f666152657175657374910131600132
&sofahessian.JavaObject{
  class: "com.alipay.sofa.rpc.core.request.SofaRequest",
  names: []string{
    "1",
  },
  values: []interface {}{
    "2",
  },
}

性能测试

─λ make bench
go test -benchmem -run="^$" -bench ^Benchmark ./...
?   	github.com/sofastack/sofa-hessian-go/sofahessianv1	[no test files]
goos: darwin
goarch: amd64
pkg: github.com/sofastack/sofa-hessian-go/sofahessianv2
BenchmarkDecodeBinary-8             	  558362	      2180 ns/op	15041.85 MB/s	       0 B/op	       0 allocs/op
BenchmarkDecodeBool-8               	33203718	        35.8 ns/op	  27.91 MB/s	       0 B/op	       0 allocs/op
BenchmarkDecodeDate-8               	14283891	        73.1 ns/op	 123.15 MB/s	       0 B/op	       0 allocs/op
BenchmarkDecodeFloat64-8            	15707289	        74.1 ns/op	  40.49 MB/s	       0 B/op	       0 allocs/op
BenchmarkDecodeInt32-8              	15519128	        82.9 ns/op	  60.31 MB/s	       0 B/op	       0 allocs/op
BenchmarkDecodeInt64-8              	15663241	        78.2 ns/op	 115.09 MB/s	       0 B/op	       0 allocs/op
BenchmarkDecodeList-8               	  751725	      2969 ns/op	   6.06 MB/s	     478 B/op	      19 allocs/op
BenchmarkDecodeMap-8                	  217478	      5185 ns/op	  14.08 MB/s	     949 B/op	      30 allocs/op
BenchmarkDecodeNil-8                	27432326	        42.6 ns/op	  23.46 MB/s	       0 B/op	       0 allocs/op
BenchmarkDecodeObject-8             	  965149	      1498 ns/op	  22.03 MB/s	     548 B/op	      13 allocs/op
BenchmarkDecodeString-8             	     818	   1333529 ns/op	 147.44 MB/s	    1370 B/op	       0 allocs/op
BenchmarkEncodeBinary-8             	  392306	      2989 ns/op	21944.34 MB/s	       0 B/op	       0 allocs/op
BenchmarkEncodeBool-8               	143134738	         8.50 ns/op	 117.64 MB/s	       0 B/op	       0 allocs/op
BenchmarkEncodeFloat64-8            	100000000	        11.0 ns/op	 819.48 MB/s	       0 B/op	       0 allocs/op
BenchmarkEncodeInt64-8              	100000000	        10.2 ns/op	 490.08 MB/s	       0 B/op	       0 allocs/op
BenchmarkEncodeInt32-8              	100000000	        10.7 ns/op	 465.65 MB/s	       0 B/op	       0 allocs/op
BenchmarkEncodeList-8               	 7413168	       161 ns/op	  12.45 MB/s	      40 B/op	       2 allocs/op
BenchmarkEncodeMap-8                	13931235	        82.9 ns/op	  24.12 MB/s	       8 B/op	       1 allocs/op
BenchmarkEncodeNil-8                	197458849	         6.12 ns/op	 163.33 MB/s	       0 B/op	       0 allocs/op
BenchmarkEncodeObject-8             	 3964602	       303 ns/op	  46.15 MB/s	      64 B/op	       3 allocs/op
BenchmarkEncodeRef-8                	88544038	        13.5 ns/op	 222.70 MB/s	       0 B/op	       0 allocs/op
BenchmarkEncodeString-8             	     716	   1662180 ns/op	 160.43 MB/s	      16 B/op	       1 allocs/op
BenchmarkEncodeAndDecodeJSON-8      	   51471	     22695 ns/op	  44.68 MB/s	    2913 B/op	      37 allocs/op
BenchmarkEncodeAndDecodeHessianV2-8   	  139880	      7979 ns/op	  56.77 MB/s	    3104 B/op	      57 allocs/op
PASS
ok  	github.com/sofastack/sofa-hessian-go/sofahessianv2	34.443s
?   	github.com/sofastack/sofa-hessian-go/javaobject	[no test files]

TODO

  1. hessian-generator: 通过编译时代码生成 Encode 和 Decode 方法,减少反射带来的负担。