80 lines
2.7 KiB
Go
80 lines
2.7 KiB
Go
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)
|
||
},
|
||
})
|
||
}
|