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)
|
|||
|
|
},
|
|||
|
|
})
|
|||
|
|
}
|