在使用jsoniter来做json相关的Marshal和UnMarshal其实是比较简单的,仅需要一行代码:
type ColorGroup struct {
ID int
Name string
Colors []string
}
group := ColorGroup{
ID: 1,
Name: "Reds",
Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
}
// 直接使用adapter.go里面的Marshal方法即可完成, so easy
b, err := jsoniter.Marshal(group)
接下来我们不是来证明jsoniter的简单和任性,而是要梳理下Marshal操作的流程:
当我们在执行jsoniter.Matshal(xxx),其中xxx为要转化的实体:
1.通过使用config.go中定义ConfigDefault.Marshal(XXX)来进行的
- Config属于struct,定义了针对json的Marshal和UnMarshal的配置要求
- API属于interface,定义操作API的行为,最主要的Marshal和UnMarshal,而其他的行为Get、NewEncoder、NewDeconder等辅助功能(一般用于用户自己定制化要求,已有的api已不能满足需求)
- ConfigDefault通过Config{}.Froze()得来的,换句话说Config转为API是通过Froze()方法来完成,在默认情况下定义ConfigDefault(默认API行为)、ConfigCompatibleWithStandardLibrary(支持标准库的行为,比如encoding/json)、ConfigFast(通过忽略float类型数据的精度保证最高效的性能)
- 说到比较特殊的frozenConfig,不得不提下Froze()方法,它用于将各种Config转变为API,而这frozenConfig就承担完成API接口定义具体行为,也就是在Froze()方法内定义一个内部frozenConfig指定一些配置项,另外指定Pool(一个常量缓存池,复用一些实例减少资源空间分配),比如streamPool、iteratorPool都是优先从Pool获取若是没有再创建,实例化。
接着进行jsoniter的本地缓存初始化,也会根据编排内容的需要提前增加一些编码器Encoder和解码器Decoder。比如:针对float的:lossyFloat32Encoder和lossyFloat64Encoder; html格式:htmlEscapedStringEncoder等等,而这些编码器Encoder和解码器Decoder最终会放到encoderExtension和decoderExtension类型分别为 map[reflect2.Type]ValEncoder和 map[reflect2.Type]ValDecoder,记录了本次进行Marshal和UnMarshal操作时所涉及的所有Encoder和Decoder,一起协作来完成对应的操作。
func (cfg Config) Froze() API {
api := &frozenConfig{
sortMapKeys: cfg.SortMapKeys,
indentionStep: cfg.IndentionStep,
objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
onlyTaggedField: cfg.OnlyTaggedField,
disallowUnknownFields: cfg.DisallowUnknownFields,
caseSensitive: cfg.CaseSensitive,
}
api.streamPool = &sync.Pool{ // 缓存stream 便于重复利用 减少GC压力
New: func() interface{} {
return NewStream(api, nil, 512)
},
}
api.iteratorPool = &sync.Pool{ // 缓存iterator 便于重复利用 减少GC压力
New: func() interface{} {
return NewIterator(api)
},
}
api.initCache() // 编码和解码本地缓存
encoderExtension := EncoderExtension{}
decoderExtension := DecoderExtension{}
if cfg.MarshalFloatWith6Digits { // 添加扩展选项的内容
api.marshalFloatWith6Digits(encoderExtension)
}
if cfg.EscapeHTML {
api.escapeHTML(encoderExtension)
}
if cfg.UseNumber {
api.useNumber(decoderExtension)
}
if cfg.ValidateJsonRawMessage {
api.validateJsonRawMessage(encoderExtension)
}
api.encoderExtension = encoderExtension
api.decoderExtension = decoderExtension
api.configBeforeFrozen = cfg
return api
}
2.真正执行Marshal操作:frozenConfig.Marshal(XXX),先来看下源码
func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) { // 序列化
stream := cfg.BorrowStream(nil) // 复用Stream
defer cfg.ReturnStream(stream) // 回收stream
stream.WriteVal(v) // 真正执行具体的操作,在下面我们会深入分析,涉及内容比较多
if stream.Error != nil {
return nil, stream.Error
}
result := stream.Buffer() // 通过将stream对应的[]byte赋值到临时[]byte 便于stream进行回收到Pool中
copied := make([]byte, len(result))
copy(copied, result) // 将stream关联的[]byte 拷贝到临时[]byte中
return copied, nil
}
- 首先得到stream 也是完成整个Marshal的核心组件,是从前面我们提到的pool来获取的,也是为了复用实例。使用完了一定记得在放回pool便于后面的操作复用(defer cfg.ReturnStream(stream))
- 接下来执行WriteVal的就是我们的核心步骤了:
1、首先要对进行Marshal的内容val检查是否=nil,若为nil,执行WriteNil,写入null;否则根据val的type获取到本地缓存中存储cachekey:reflect2.RTypeOf(val)【注:reflect2是对原有的reflect反射进行了包装,自定义了eface,而它包括了两部分:type和data均为指针pointer】,再调用cfg.encoderCache来获取config本地缓存中的encoder,不过可能config本地缓存中并没有产生对应的encoder比如第一次调用时,则需要create
2、新建type包装类:由于第一步是从缓存获取对应的eface的rtype对应的指针,由于一些操作的延迟或第一次操作 会导致本地缓存中并没有相关内容;那么接下来我们需要根据参数的反射类型来进行type包装类操作:通过reflect2.TypeOf函数内部调用ConfigUnsafe.TypeOf(obj),该操作过程也会重新步骤1的过程,进行二次检查,若是本地缓存仍未有,则会继续通过Type2(reflect.Type)来操作,提取反射类型reflect.Type对应的eface中data部分的指针当成本地缓存key,继续从缓冲中获取,若是本地缓存还没有 则需要根据反射类型reflect.Type进行创建新的wrap Type
3、根据新建的包装类型WrapType来创建对应的ValEncoder编码器:
接着仍然从本地缓存根据给定的RType来查询对应的encoder编码器,在缓存仍没有的情况下,需要手动新建encoder编码器,首先新建ctx并指定frozenConfig以及decoders、encoders两个本地缓存,再根据ctx和wraptype对应的rtype创建encoder,并添加到本地缓存中。
至此得到编排的编码器encoder - 最后提取出stream buffer中的内容到result,在定义临时变量copied通过copy result的内容,最终将临时变量copied返回,这里面场景临时变量的原因是为了防止使用stream.Buffer会导致ReturnStream操作不可达(result和stream.Buffer关联导致ReturnStream操作无法完成 出现panic)
在第二大步中的第3步涉及到的encoderOfType是根据ctx和relect2.Type来创建ValEncoder的:首先是调用getTypeEncoderFromExtension本质是调用内部函数_getTypeEncoderFromExtension(),在该函数内部首先遍历extensions并根据reflect2.Type来创建编码器Encoder,若是extensions已存在则完成编码器的创建并返回结果;否则根据config的encoderExtension来创建encoder,而所有内部的extension均未完成编码器encoder的创建,则需要使用extraExtensions来遍历创建编码器encoder,而上述的无论内部还是外部的Extensions都未完成编码器的创建。则需要到本地缓存map:typeEncoders根据typeName来查找,至此仍未完成的话,则根据type.Kind是否为reflect.Ptr,进行强制转换为*reflect2.UnsafePtrType,再根据UnsafePtrType.Elem()到typeEncoders中查找,若是存在则输出OptionalEncoder;否则则代表该类型的encoder不能创建完成 ,也即不能完成相关内容的编排。
1、reflect.go中的EncoderOf
func (cfg *frozenConfig) EncoderOf(typ reflect2.Type) ValEncoder {
cacheKey := typ.RType() // 根据reflect2.Type类型获取对应的cache key
encoder := cfg.getEncoderFromCache(cacheKey)
if encoder != nil { // 获取cache中的encoder
return encoder
}
ctx := &ctx{ // 本地cache不存在对应的编码器encoder 需要新建
frozenConfig: cfg,
prefix: "",
decoders: map[reflect2.Type]ValDecoder{},
encoders: map[reflect2.Type]ValEncoder{},
}
encoder = encoderOfType(ctx, typ) // 根据ctx和type创建编码器encoder
if typ.LikePtr() { // 该类型类似指针 需要通过onePtrEncoder进行包装
encoder = &onePtrEncoder{encoder}
}
cfg.addEncoderToCache(cacheKey, encoder) // 新建的编码器encoder放入本地缓存
return encoder
}
2、reflect.go中的encoderOfType
func encoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder {
encoder := getTypeEncoderFromExtension(ctx, typ) // 从扩展的编码器encoder:extensions中获取encoder
if encoder != nil {
return encoder
}
encoder = createEncoderOfType(ctx, typ) // 扩展编码器中不存在对应类型的编码器 需要新建
for _, extension := range extensions {
encoder = extension.DecorateEncoder(typ, encoder)
}
encoder = ctx.encoderExtension.DecorateEncoder(typ, encoder)
for _, extension := range ctx.extraExtensions {
encoder = extension.DecorateEncoder(typ, encoder)
}
return encoder
}
// 真正完成对应类型Type的编码器Encoder创建
func createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder {
encoder := ctx.encoders[typ]
if encoder != nil {
return encoder
}
placeholder := &placeholderEncoder{}
ctx.encoders[typ] = placeholder
encoder = _createEncoderOfType(ctx, typ)
placeholder.encoder = encoder
return encoder
}
func _createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder {
encoder := createEncoderOfJsonRawMessage(ctx, typ)
if encoder != nil {
return encoder
}
encoder = createEncoderOfJsonNumber(ctx, typ)
if encoder != nil {
return encoder
}
encoder = createEncoderOfMarshaler(ctx, typ)
if encoder != nil {
return encoder
}
encoder = createEncoderOfAny(ctx, typ)
if encoder != nil {
return encoder
}
encoder = createEncoderOfNative(ctx, typ)
if encoder != nil {
return encoder
}
kind := typ.Kind()
switch kind {
case reflect.Interface:
return &dynamicEncoder{typ}
case reflect.Struct:
return encoderOfStruct(ctx, typ)
case reflect.Array:
return encoderOfArray(ctx, typ)
case reflect.Slice:
return encoderOfSlice(ctx, typ)
case reflect.Map:
return encoderOfMap(ctx, typ)
case reflect.Ptr:
return encoderOfOptional(ctx, typ)
default:
return &lazyErrorEncoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())}
}
}
网友评论