暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

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


codec factory 的创建

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

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

newSerializersForScheme() 的源码如下:

// 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() 的源码如下:
// 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 相关的源代码创建如下:
// 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 的序列化和反序列化过程。

文章转载自TA码字,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论