← Назад к вопросам

Какие знаешь Registry?

2.0 Middle🔥 123 комментариев
#Контейнеризация и DevOps

Комментарии (3)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Реестры (Registry) в Go

В контексте Go-разработки под Registry обычно понимают паттерн проектирования "Реестр" (или "Регистр"), который представляет собой централизованное хранилище объектов, доступное глобально или в рамках определенного контекста. Это структурный паттерн, используемый для управления зависимостями, сервисами или компонентами системы.

Основные типы реестров в Go

1. Service Registry (Реестр сервисов)

Используется в микросервисной архитектуре для отслеживания доступных экземпляров сервисов.

package main

import "sync"

type ServiceRegistry struct {
    mu       sync.RWMutex
    services map[string]string // serviceName -> endpoint
}

func NewServiceRegistry() *ServiceRegistry {
    return &ServiceRegistry{
        services: make(map[string]string),
    }
}

func (sr *ServiceRegistry) Register(serviceName, endpoint string) {
    sr.mu.Lock()
    defer sr.mu.Unlock()
    sr.services[serviceName] = endpoint
}

func (sr *ServiceRegistry) GetEndpoint(serviceName string) (string, bool) {
    sr.mu.RLock()
    defer sr.mu.RUnlock()
    endpoint, exists := sr.services[serviceName]
    return endpoint, exists
}

2. Dependency Injection Registry

Реестр для управления зависимостями в приложениях с внедрением зависимостей (DI).

package di

import (
    "fmt"
    "sync"
)

type Container struct {
    mu          sync.RWMutex
    dependencies map[string]interface{}
    factories   map[string]func() interface{}
}

func NewContainer() *Container {
    return &Container{
        dependencies: make(map[string]interface{}),
        factories:   make(map[string]func() interface{}),
    }
}

func (c *Container) RegisterSingleton(name string, instance interface{}) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.dependencies[name] = instance
}

func (c *Container) RegisterFactory(name string, factory func() interface{}) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.factories[name] = factory
}

func (c *Container) Get(name string) (interface{}, error) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    
    if dep, exists := c.dependencies[name]; exists {
        return dep, nil
    }
    
    if factory, exists := c.factories[name]; exists {
        return factory(), nil
    }
    
    return nil, fmt.Errorf("dependency %s not found", name)
}

3. Registry Pattern для конфигурации

Централизованное хранение конфигурации приложения.

package config

import (
    "encoding/json"
    "os"
    "sync"
)

type ConfigRegistry struct {
    mu     sync.RWMutex
    config map[string]interface{}
}

func (cr *ConfigRegistry) LoadFromFile(path string) error {
    cr.mu.Lock()
    defer cr.mu.Unlock()
    
    file, err := os.Open(path)
    if err != nil {
        return err
    }
    defer file.Close()
    
    return json.NewDecoder(file).Decode(&cr.config)
}

func (cr *ConfigRegistry) Get(key string) interface{} {
    cr.mu.RLock()
    defer cr.mu.RUnlock()
    return cr.config[key]
}

func (cr *ConfigRegistry) Set(key string, value interface{}) {
    cr.mu.Lock()
    defer cr.mu.Unlock()
    cr.config[key] = value
}

4. Plugin Registry

Реестр для динамической загрузки и управления плагинами.

package plugin

import (
    "plugin"
    "sync"
)

type PluginRegistry struct {
    mu      sync.RWMutex
    plugins map[string]*plugin.Plugin
}

func (pr *PluginRegistry) LoadPlugin(name, path string) error {
    pr.mu.Lock()
    defer pr.mu.Unlock()
    
    p, err := plugin.Open(path)
    if err != nil {
        return err
    }
    
    pr.plugins[name] = p
    return nil
}

func (pr *PluginRegistry) GetSymbol(pluginName, symbolName string) (interface{}, error) {
    pr.mu.RLock()
    defer pr.mu.RUnlock()
    
    p, exists := pr.plugins[pluginName]
    if !exists {
        return nil, ErrPluginNotFound
    }
    
    return p.Lookup(symbolName)
}

Ключевые особенности и лучшие практики

Потокобезопасность

  • Все операции с реестром должны быть thread-safe
  • Используйте sync.RWMutex для конкурентного доступа
  • Чтение должно блокироваться только на запись

Инициализация

// Ленивая инициализация
var (
    registry *ServiceRegistry
    once     sync.Once
)

func GetRegistry() *ServiceRegistry {
    once.Do(func() {
        registry = NewServiceRegistry()
    })
    return registry
}

Жизненный цикл

  1. Регистрация компонентов при инициализации
  2. Резолвинг зависимостей во время выполнения
  3. Очистка при завершении работы приложения

Преимущества использования Registry

  • Централизованное управление зависимостями
  • Упрощение тестирования через моки и стабы
  • Гибкость в замене реализаций
  • Снижение связности между компонентами

Недостатки и ограничения

  • Глобальное состояние может усложнить отладку
  • Потенциальные утечки памяти при неправильном управлении жизненным циклом
  • Сложность при использовании в конкурентных сценариях

Альтернативы и смежные подходы

  1. Функциональная зависимость вместо глобального реестра
  2. Контекст (context.Context) для передачи зависимостей
  3. Специализированные библиотеки: Uber Dig, Google Wire
  4. Встроенные механизмы Go: init() функции, глобальные переменные (с осторожностью)

Пример комплексного использования

package app

import (
    "database/sql"
    "log"
    "sync"
)

type AppRegistry struct {
    db     *sql.DB
    cache  Cache
    logger *log.Logger
    mu     sync.RWMutex
}

func (ar *AppRegistry) DB() *sql.DB {
    ar.mu.RLock()
    defer ar.mu.RUnlock()
    return ar.db
}

func (ar *AppRegistry) SetDB(db *sql.DB) {
    ar.mu.Lock()
    defer ar.mu.Unlock()
    ar.db = db
}

// Аналогичные методы для cache и logger

Registry в Go — это мощный паттерн, который требует аккуратного использования. При правильной реализации он значительно упрощает архитектуру приложения, но при неправильном — может создать серьезные проблемы с поддерживаемостью и тестированием. Ключевой принцип — баланс между удобством использования и соблюдением принципов чистой архитектуры.

Какие знаешь Registry? | PrepBro