美文网首页Golang
关于jsoniter源码-Marshal

关于jsoniter源码-Marshal

作者: 神奇的考拉 | 来源:发表于2018-12-10 14:36 被阅读28次

    在使用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())}
        }
    }
    

    相关文章

      网友评论

        本文标题:关于jsoniter源码-Marshal

        本文链接:https://www.haomeiwen.com/subject/tkxxhqtx.html