Golang如何在运行时动态切换不同的JSON编码器

Golang如何在运行时动态切换不同的JSON编码器 如何保持 encoding/json 作为默认选项,但允许在运行时覆盖为不同的 JSON 编码器,例如 jsoniter

2 回复

没有神奇的方法可以做到这一点,你需要编写明确的代码,以某种方式决定选择哪一个。

更多关于Golang如何在运行时动态切换不同的JSON编码器的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中实现运行时动态切换JSON编码器,可以通过接口抽象和依赖注入来实现。下面是一个具体实现方案:

package main

import (
	"encoding/json"
	"fmt"
	"sync"
	
	jsoniter "github.com/json-iterator/go"
)

// JSONEncoder 定义统一的JSON编码接口
type JSONEncoder interface {
	Marshal(v interface{}) ([]byte, error)
	Unmarshal(data []byte, v interface{}) error
}

// 默认编码器 - encoding/json
type StdJSONEncoder struct{}

func (e *StdJSONEncoder) Marshal(v interface{}) ([]byte, error) {
	return json.Marshal(v)
}

func (e *StdJSONEncoder) Unmarshal(data []byte, v interface{}) error {
	return json.Unmarshal(data, v)
}

// 高性能编码器 - jsoniter
type JsoniterEncoder struct {
	api jsoniter.API
}

func NewJsoniterEncoder() *JsoniterEncoder {
	return &JsoniterEncoder{
		api: jsoniter.ConfigCompatibleWithStandardLibrary,
	}
}

func (e *JsoniterEncoder) Marshal(v interface{}) ([]byte, error) {
	return e.api.Marshal(v)
}

func (e *JsoniterEncoder) Unmarshal(data []byte, v interface{}) error {
	return e.api.Unmarshal(data, v)
}

// JSON编码器管理器
type JSONEncoderManager struct {
	currentEncoder JSONEncoder
	encoders       map[string]JSONEncoder
	mu             sync.RWMutex
}

func NewJSONEncoderManager() *JSONEncoderManager {
	mgr := &JSONEncoderManager{
		encoders: make(map[string]JSONEncoder),
	}
	
	// 注册默认编码器
	mgr.RegisterEncoder("std", &StdJSONEncoder{})
	mgr.RegisterEncoder("jsoniter", NewJsoniterEncoder())
	
	// 设置默认编码器
	mgr.SwitchEncoder("std")
	
	return mgr
}

func (m *JSONEncoderManager) RegisterEncoder(name string, encoder JSONEncoder) {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.encoders[name] = encoder
}

func (m *JSONEncoderManager) SwitchEncoder(name string) error {
	m.mu.Lock()
	defer m.mu.Unlock()
	
	encoder, exists := m.encoders[name]
	if !exists {
		return fmt.Errorf("encoder %s not registered", name)
	}
	
	m.currentEncoder = encoder
	return nil
}

func (m *JSONEncoderManager) GetEncoder() JSONEncoder {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return m.currentEncoder
}

// 使用示例
type User struct {
	Name  string `json:"name"`
	Email string `json:"email"`
}

func main() {
	// 初始化编码器管理器
	encoderMgr := NewJSONEncoderManager()
	
	user := User{
		Name:  "John Doe",
		Email: "john@example.com",
	}
	
	// 使用默认编码器(encoding/json)
	encoder := encoderMgr.GetEncoder()
	data, _ := encoder.Marshal(user)
	fmt.Printf("Default encoder: %s\n", string(data))
	
	// 运行时切换到jsoniter
	encoderMgr.SwitchEncoder("jsoniter")
	encoder = encoderMgr.GetEncoder()
	data, _ = encoder.Marshal(user)
	fmt.Printf("Switched to jsoniter: %s\n", string(data))
	
	// 切换回标准编码器
	encoderMgr.SwitchEncoder("std")
	encoder = encoderMgr.GetEncoder()
	
	var decodedUser User
	_ = encoder.Unmarshal(data, &decodedUser)
	fmt.Printf("Decoded with std: %+v\n", decodedUser)
}

如果需要更细粒度的控制,可以为每个包或模块提供独立的编码器实例:

// 全局编码器管理器
var globalEncoderMgr = NewJSONEncoderManager()

// 包级别的编码器获取函数
func GetJSONEncoder() JSONEncoder {
	return globalEncoderMgr.GetEncoder()
}

func SetJSONEncoder(name string) error {
	return globalEncoderMgr.SwitchEncoder(name)
}

// 在业务代码中使用
func processUser(user User) ([]byte, error) {
	encoder := GetJSONEncoder()
	return encoder.Marshal(user)
}

这个方案通过接口抽象实现了编码器的解耦,支持运行时动态切换,同时保持了encoding/json作为默认选项。sync.RWMutex确保了并发安全,可以安全地在多个goroutine中使用。

回到顶部