Files

80 lines
2.7 KiB
Go
Raw Permalink Normal View History

2026-04-13 08:14:09 +03:00
package main
// Fx с ОБЩИМИ интерфейсами — чистый и простой пример.
//
// Сравните:
// cmd/fx-di/main.go — consumer-defined interfaces (Go-идиома) → 330 строк
// cmd/fx-di-shared/ — shared interfaces (Java-подход) → вот этот файл
//
// Разница — только в подходе к определению интерфейсов.
// Когда один тип → один интерфейс, Fx работает без fx.Out/fx.In/named-тегов.
//
// Это НЕ рекомендация так писать на Go. Это демонстрация того,
// под какую архитектуру Fx был спроектирован.
//
// Lifecycle:
// Fx управляет жизненным циклом компонентов через хуки OnStart/OnStop.
// При запуске — вызывает OnStart в порядке зависимостей (сначала DB, потом сервисы).
// При остановке — вызывает OnStop в обратном порядке (сначала сервер, потом DB).
// Отправьте SIGINT (Ctrl+C) чтобы увидеть порядок остановки в логах.
//
// Хотите увидеть как это масштабируется на несколько команд?
// Смотрите cmd/fx-di-modules/ — тот же код, но каждый домен в своём файле.
import (
"context"
"log/slog"
"net"
"net/http"
"go.uber.org/fx"
)
func main() {
fx.New(
fx.Provide(
newDB,
newCache,
newEventBus,
newUserRepo,
newSessionRepo,
newNotificationRepo,
newAuthService,
newUserService,
newNotificationService,
newHandler,
),
fx.Invoke(startHTTPServer),
// Вот и всё. 10 провайдеров, 1 invoke. Fx разрулил сам.
// Потому что один тип → один интерфейс → нет неоднозначности.
//
// А lifecycle хуки (OnStart/OnStop) — внутри провайдеров newDB, newCache
// и startHTTPServer. Fx сам вызовет их в правильном порядке.
).Run()
}
func startHTTPServer(lc fx.Lifecycle, h *handler) {
srv := &http.Server{
Addr: ":8080",
Handler: h.routes(),
}
lc.Append(fx.Hook{
OnStart: func(ctx context.Context) error {
ln, err := net.Listen("tcp", srv.Addr)
if err != nil {
return err
}
slog.Info("HTTP-сервер запущен", "addr", srv.Addr)
go srv.Serve(ln)
return nil
},
OnStop: func(ctx context.Context) error {
slog.Info("HTTP-сервер останавливается...")
return srv.Shutdown(ctx)
},
})
}