前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >K8s源码分析(8)-codec和codec factory的创建

K8s源码分析(8)-codec和codec factory的创建

作者头像
TA码字
发布2021-11-02 16:25:52
7550
发布2021-11-02 16:25:52
举报
文章被收录于专栏:TA码字TA码字

上一篇文章,我们主要介绍了 codec 组件和 codec factory 组件,这两个组件主要实现了内部版本和其他版本之间转化的序列化以及反序列化。包括了这两个组件实现的关键接口,以及这两个组件会由哪些关键成员组成。在这里我们主要介绍 codec 和 codec factory 的创建。

codec factory 的创建

codec factory 对象的创建被定义在方法 NewCodecFactory() 中,该方法内部调用了 newSerializersForScheme() 方法来创建支持不同数据格式的 Serializer 对象,然后又调用 newCodecFactory() 方法来实现对象创建。

newSerializersForScheme() 方法主要是创建支持各种数据格式 (json, yaml, protobuf 等) 的 serializer 对象,例如之前我们介绍支持 jason 格式的 serializer.json.Serializer,其核心逻辑如下:

newSerializersForScheme() 的源码如下:

代码语言:javascript
复制
// k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go
func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, options CodecFactoryOptions) []serializerType {
  jsonSerializer := json.NewSerializerWithOptions(
    mf, scheme, scheme,
    json.SerializerOptions{Yaml: false, Pretty: false, Strict: options.Strict},
  )
  jsonSerializerType := serializerType{
    AcceptContentTypes: []string{runtime.ContentTypeJSON},
    ContentType:        runtime.ContentTypeJSON,
    FileExtensions:     []string{"json"},
    EncodesAsText:      true,
    Serializer:         jsonSerializer,

    Framer:           json.Framer,
    StreamSerializer: jsonSerializer,
  }
  if options.Pretty {
    jsonSerializerType.PrettySerializer = json.NewSerializerWithOptions(
      mf, scheme, scheme,
      json.SerializerOptions{Yaml: false, Pretty: true, Strict: options.Strict},
    )
  }

  yamlSerializer := json.NewSerializerWithOptions(
    mf, scheme, scheme,
    json.SerializerOptions{Yaml: true, Pretty: false, Strict: options.Strict},
  )
  protoSerializer := protobuf.NewSerializer(scheme, scheme)
  protoRawSerializer := protobuf.NewRawSerializer(scheme, scheme)

  serializers := []serializerType{
    jsonSerializerType,
    {
      AcceptContentTypes: []string{runtime.ContentTypeYAML},
      ContentType:        runtime.ContentTypeYAML,
      FileExtensions:     []string{"yaml"},
      EncodesAsText:      true,
      Serializer:         yamlSerializer,
    },
    {
      AcceptContentTypes: []string{runtime.ContentTypeProtobuf},
      ContentType:        runtime.ContentTypeProtobuf,
      FileExtensions:     []string{"pb"},
      Serializer:         protoSerializer,

      Framer:           protobuf.LengthDelimitedFramer,
      StreamSerializer: protoRawSerializer,
    },
  }

  for _, fn := range serializerExtensions {
    if serializer, ok := fn(scheme); ok {
      serializers = append(serializers, serializer)
    }
  }
  return serializers
}

在 newCodecFactory() 这个方法里面,主要逻辑就是调用 newSerializersForScheme()方法,用来生成可以支持各种不同数据类型的 serializerType 数组, 然后利用该数组进行封装创建 codc factory,逻辑如下:

方法 newCodecFactory() 的源码如下:

代码语言:javascript
复制
// k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go
func newCodecFactory(scheme *runtime.Scheme, serializers []serializerType) CodecFactory {
  decoders := make([]runtime.Decoder, 0, len(serializers))
  var accepts []runtime.SerializerInfo
  alreadyAccepted := make(map[string]struct{})

  var legacySerializer runtime.Serializer
  for _, d := range serializers {
    decoders = append(decoders, d.Serializer)
    for _, mediaType := range d.AcceptContentTypes {
      if _, ok := alreadyAccepted[mediaType]; ok {
        continue
      }
      alreadyAccepted[mediaType] = struct{}{}
      info := runtime.SerializerInfo{
        MediaType:        d.ContentType,
        EncodesAsText:    d.EncodesAsText,
        Serializer:       d.Serializer,
        PrettySerializer: d.PrettySerializer,
      }

      mediaType, _, err := mime.ParseMediaType(info.MediaType)
      if err != nil {
        panic(err)
      }
      parts := strings.SplitN(mediaType, "/", 2)
      info.MediaTypeType = parts[0]
      info.MediaTypeSubType = parts[1]

      if d.StreamSerializer != nil {
        info.StreamSerializer = &runtime.StreamSerializerInfo{
          Serializer:    d.StreamSerializer,
          EncodesAsText: d.EncodesAsText,
          Framer:        d.Framer,
        }
      }
      accepts = append(accepts, info)
      if mediaType == runtime.ContentTypeJSON {
        legacySerializer = d.Serializer
      }
    }
  }
  if legacySerializer == nil {
    legacySerializer = serializers[0].Serializer
  }

  return CodecFactory{
    scheme:    scheme,
    universal: recognizer.NewDecoder(decoders...),

    accepts: accepts,

    legacySerializer: legacySerializer,
  }
}

codec 的创建

codec factory 对象的 DecoderToVersion() 方法和 EncoderForVersion() 方法会创建 codec 对象。而这两个方法又都会去调用相同的 NewDefaultingCodecForScheme() 方法,最终这个方法又调用 NewCodec() 实现创建。

DecoderToVersion()和EncoderForVersion() 方法逻辑如下:

codec 相关的源代码创建如下:

代码语言:javascript
复制
// k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go
func (f CodecFactory) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
  return f.CodecForVersions(nil, decoder, nil, gv)
}

func (f CodecFactory) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
  return f.CodecForVersions(encoder, nil, gv, nil)
}

func (f CodecFactory) CodecForVersions(encoder runtime.Encoder, decoder runtime.Decoder, encode runtime.GroupVersioner, decode runtime.GroupVersioner) runtime.Codec {
  // TODO: these are for backcompat, remove them in the future
  if encode == nil {
    encode = runtime.DisabledGroupVersioner
  }
  if decode == nil {
    decode = runtime.InternalGroupVersioner
  }
  return versioning.NewDefaultingCodecForScheme(f.scheme, encoder, decoder, encode, decode)
}

// staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning.go
func NewDefaultingCodecForScheme(
  scheme *runtime.Scheme,
  encoder runtime.Encoder,
  decoder runtime.Decoder,
  encodeVersion runtime.GroupVersioner,
  decodeVersion runtime.GroupVersioner,
) runtime.Codec {
  return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, scheme, encodeVersion, decodeVersion, scheme.Name())
}

func NewCodec(
  encoder runtime.Encoder,
  decoder runtime.Decoder,
  convertor runtime.ObjectConvertor,
  creater runtime.ObjectCreater,
  typer runtime.ObjectTyper,
  defaulter runtime.ObjectDefaulter,
  encodeVersion runtime.GroupVersioner,
  decodeVersion runtime.GroupVersioner,
  originalSchemeName string,
) runtime.Codec {
  internal := &codec{
    encoder:   encoder,
    decoder:   decoder,
    convertor: convertor,
    creater:   creater,
    typer:     typer,
    defaulter: defaulter,

    encodeVersion: encodeVersion,
    decodeVersion: decodeVersion,

    identifier: identifier(encodeVersion, encoder),

    originalSchemeName: originalSchemeName,
  }
  return internal
}

目前先我们写到这里,在下一篇文章中我们继续来介绍 codec 的序列化和反序列化过程。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-10-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TA码字 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档