gs

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 4, 2026 License: Apache-2.0 Imports: 25 Imported by: 71

Documentation

Overview

Package gs provides dependency injection (DI) and application container inspired by Java Spring Framework and Spring Boot.

Core Design Principles (aligned with Spring):

  1. IoC (Inversion of Control): The container manages bean lifecycle, instantiation, and dependency injection. Your code doesn't manually new-up dependencies - container creates everything and wires them together.

  2. DI (Dependency Injection): Beans declare dependencies via constructor parameters, container automatically resolves and injects matching beans. This promotes loose coupling and testability.

  3. Conditional Auto-Configuration: Modules can be conditionally activated based on configuration properties and existing beans, enabling a starter-style auto-configuration system just like Spring Boot.

  4. Early Registration: All beans and modules MUST be registered during package initialization (init() phase). This guarantees everything is registered before application startup, making the entire boot process predictable.

Key Concepts mapping from Spring:

Java/Spring Annotation    | Go-Spring API
------------------------- | ------------------------------
@Bean / <bean>            | gs.Provide(...)
@Value("${prop.key}")     | gs.TagArg("${prop.key}")
@Conditional              | gs.Condition
@ConditionalOnProperty    | gs.OnProperty(...)
@ConditionalOnBean        | gs.OnBean[...]()
@ConditionalOnMissingBean | gs.OnMissingBean[...]()
Spring Boot AutoConfig    | gs.Module(condition, func)

Go-Spring Extensions:

  • Group: Bulk registers multiple beans from a configuration map. When you have a list/map of configurations in YAML, it automatically creates one bean per entry. This is great for multiple databases, multiple HTTP clients, dynamic plugin loading, etc.
  • Dync: Dynamic configuration that automatically updates when the underlying configuration changes.

Typical Usage:

// Step 1: Register beans in package-level init() function
func init() {
    // Register a simple bean
    gs.Provide(&MyServiceImpl{})

    // Register a conditional auto-configuration module (like Spring Boot starter)
    gs.Module(gs.OnProperty("redis.enabled"),
        func(r gs.BeanProvider, p flatten.Storage) error {
            r.Provide(NewRedisClient)
            return nil
        })
}

// Step 2: Boot the application in main()
func main() {
    gs.Configure(func(app gs.App) {
        app.Property("server.port", "8080")
    }).Run()
}

Index

Constants

View Source
const (
	Version = "go-spring@v1.3.0"
	Website = "https://github.com/go-spring/"
)

Variables

This section is empty.

Functions

func As added in v1.2.0

func As[T any]() reflect.Type

As returns the reflect.Type of the given generic interface type T. It is typically used with [BeanDefinition.Export] to register interfaces that a bean implements, allowing dependency injection by interface type.

Example:

type Service interface {
    Serve() error
}

type ServiceImpl struct{}

func (s *ServiceImpl) Serve() error { return nil }

gs.Provide(&ServiceImpl{}).Export(gs.As[Service]())
func Banner(banner string)

Banner sets a custom app banner.

func BindArg added in v1.2.0

func BindArg(fn any, args ...Arg) *gs_arg.BindArg

BindArg creates an argument whose value is computed dynamically by a function. It executes the function at bean creation time to get the actual argument value, and supports attaching conditions that control whether the argument is accepted.

Use cases:

  • Conditional bean creation based on runtime state
  • Complex initialization logic that requires multiple dependencies
  • Lazy evaluation of expensive resources

Example:

gs.Provide(
    func(logger *Logger) *Service { ... },
    gs.BindArg(func() (*Logger, error) {
        return createLogger()
    }).Condition(gs.OnProperty("logging.enabled"))
)

func Group added in v1.2.3

func Group[T any, R any](tag string, fn func(c T) (R, error), d func(R) error)

Group reads a map from the specified configuration property, then iterates over each entry and creates one bean per entry using the constructor fn. The map key becomes the bean name, and the map value is passed to fn as the configuration for constructing the bean. An optional destructor d can be provided for cleanup when the application shuts down.

Use cases:

  • Multiple database connections from configuration
  • Multiple dynamic service clients configured in YAML
  • Plugin architectures with configurable components

Example:

// Register multiple HTTP clients from configuration
gs.Group(
    "${http.clients}",
    func(cfg HTTPClientConfig) (*HTTPClient, error) {
        return NewHTTPClient(cfg)
    },
    func(c *HTTPClient) error {
        return c.Close()
    },
)

Corresponding YAML configuration:

http:
  clients:
    serviceA:  # <- "serviceA" becomes the bean name
      baseURL: "http://a.example.com"
      timeout: 30s
    serviceB:  # <- "serviceB" becomes the bean name
      baseURL: "http://b.example.com"
      timeout: 60s

func Module added in v1.2.3

func Module(c PropertyCondition, fn ModuleFunc)

Module registers a configuration module that is conditionally activated based on property values.

Limitations:

  • MUST be called during init phase (will panic otherwise)
  • Condition is evaluated at module execution time, not registration time
  • Module functions cannot be called directly; they are managed by the framework

Use cases:

  • Starter modules that auto-configure based on classpath/dependencies
  • Feature modules that activate based on configuration flags
  • Modular application architecture

Example:

gs.Module(gs.OnProperty("redis.enabled"),
func(r gs.BeanProvider, p flatten.Storage) error {
    r.Provide(NewRedisClient)
    return nil
})

func Provide

func Provide(objOrCtor any, args ...Arg) *gs_bean.BeanDefinition

Provide registers a global bean definition. It must be called during package initialization (init phase). Calling it after application configuration has started will panic. It accepts either an existing instance or a constructor function. The optional args are used to bind parameters for the constructor or to provide explicit injection values.

Parameters:

  • objOrCtor: bean instance (struct pointer) or constructor function
  • args: optional arguments for parameter binding

Limitations:

  • MUST be called during init phase (before application startup)
  • Will panic if called after initialization is complete
  • Bean must be a reference type (pointer), not a value type
  • Constructor functions must have signature: func(...)bean or func(...)(bean, error)

Example:

// Register an instance
gs.Provide(&MyService{})

// Register a constructor with arguments
gs.Provide(NewMyService, gs.TagArg("${config.key}"))

// Chain configuration
gs.Provide(&Logger{}).Name("default").InitMethod("Start")

func RegisterExpressFunc added in v1.2.0

func RegisterExpressFunc(name string, fn any)

RegisterExpressFunc registers a custom expression function that can be used inside conditional expressions. It should be called during application initialization.

func Run

func Run()

Run creates and starts a new application using default settings. Blocks until termination signal is received (SIGINT/SIGTERM).

func RunAsync added in v1.2.2

func RunAsync() (stop func(), err error)

RunAsync runs the application asynchronously and returns a function to stop the application. Convenience wrapper that creates a new AppStarter.

Returns:

  • stop: Function to gracefully shutdown the application
  • err: Error if application failed to start (nil on success)

Usage:

stop, err := gs.RunAsync()
if err != nil {
    log.Fatal(err)
}
defer stop() // Ensure cleanup
// ... do work ...

func RunTest added in v1.3.0

func RunTest(t *testing.T, f any)

RunTest runs a test function using a new application instance. Convenience wrapper that creates a fresh AppStarter for testing.

Parameters:

  • t: Testing.T instance for test reporting and failure handling
  • f: Test function accepting exactly one pointer-to-struct argument

Requirements:

  • Test function signature: func(*TestStruct)
  • TestStruct fields can use autowire/value tags for injection
  • Struct is registered as root bean with full dependency injection

Example:

func TestExample(t *testing.T) {
    gs.RunTest(t, func(ts *struct {
        DB *Database `autowire:""`
    }) {
        // ts.DB is auto-injected
        result := ts.DB.Query(...)
        assert.NotNil(t, result)
    })
}

Types

type App

type App interface {
	// Property sets a key-value property in the application configuration.
	Property(key string, val string)
	// Root marks a bean as the root bean.
	Root(obj any) *gs_bean.BeanDefinition
	// Provide registers an object or constructor as a bean in the application.
	Provide(objOrCtor any, args ...gs.Arg) *gs_bean.BeanDefinition
}

App defines the configuration interface of a Go-Spring application. Methods on App are only valid during application configuration and must not be called after the application has started.

type AppStarter added in v1.2.0

type AppStarter struct {
	// contains filtered or unexported fields
}

AppStarter wraps a gs_app.App and manages its lifecycle. It provides methods for initialization, configuration, starting, stopping, running, and testing the application.

func Configure added in v1.3.0

func Configure(cfg func(App)) *AppStarter

Configure creates a new application and registers a configuration function that will be applied before the application starts.

Example:

gs.Configure(func(app gs.App) {
    app.Property("server.port", "8080")
    app.Provide(&MyService{})
}).Run()

func Web

func Web(enable bool) *AppStarter

Web creates a new application with web server enabled.

func (*AppStarter) Configure added in v1.3.0

func (s *AppStarter) Configure(cfg func(App)) *AppStarter

Configure allows you to modify the application configuration. Accumulates configuration functions - each call adds to the chain. Configuration functions execute in order of registration during startApp().

Important:

  • Multiple Configure() calls accumulate, not replace
  • Order matters: earlier configs execute before later ones
  • All configs run before app.Start() is called

func (*AppStarter) Run added in v1.2.0

func (s *AppStarter) Run()

Run starts the application, applies configuration, and waits for termination signals (e.g., SIGTERM, Ctrl+C) to trigger a graceful shutdown.

func (*AppStarter) RunAsync added in v1.2.2

func (s *AppStarter) RunAsync() (stop func(), err error)

RunAsync runs the application asynchronously and returns a function to stop the application.

Returns:

  • stop: Closure that calls ShutDown() and WaitForShutdown()
  • err: Startup error if startApp() fails

Behavior:

  • Calls startApp() synchronously to initialize application
  • On success: Returns stop function for manual shutdown control
  • On error: Returns no-op function and error

Caller Responsibility:

  • Must call stop() to ensure graceful shutdown
  • Should handle startup errors appropriately
  • Can use defer for guaranteed cleanup

func (*AppStarter) RunTest added in v1.3.0

func (s *AppStarter) RunTest(t *testing.T, f any)

RunTest runs a user-defined test function with an auto-created test object. It extracts the test object type from the test function parameter, creates the test object, registers it as a root bean, initializes the application, starts the application, executes the test, and ensures graceful shutdown.

type Arg added in v1.2.0

type Arg = gs.Arg

Arg represents an argument used when binding constructor parameters. Args are primarily used in:

  • Constructor parameter injection via gs.Provide(func(...) T, args...)
  • Method-based bean definition with custom arguments
  • Conditional bean creation based on runtime conditions

func IndexArg added in v1.2.0

func IndexArg(n int, arg Arg) Arg

IndexArg targets a specific constructor parameter by index and provides the given Arg as its value.

Use cases:

  • Skipping optional parameters
  • Providing arguments out of order
  • Injecting values into variadic functions

Example:

// Inject value into the 3rd parameter (index 2)
gs.Provide(func(a, b, c string) *Bean { ... }, gs.IndexArg(2, gs.ValueArg("value")))

func TagArg added in v1.2.0

func TagArg(tag string) Arg

TagArg creates an argument that injects a property or bean identified by the specified struct-tag expression.

Example:

// Bind a configuration property
gs.Provide(func(cfg string) *MyBean { ... }, gs.TagArg("${app.name}"))

// Wire a dependency
gs.Provide(func(svc Service) *MyBean { ... }, gs.TagArg(""))

func ValueArg added in v1.2.0

func ValueArg(v any) Arg

ValueArg creates an argument with a fixed value. This is useful for injecting constant values or pre-created instances into constructors.

Example:

gs.Provide(func(timeout time.Duration) *Client { ... }, gs.ValueArg(30*time.Second))

type BeanID added in v1.1.1

type BeanID = gs.BeanID

BeanID represents a selector for a bean.

func BeanIDFor added in v1.3.0

func BeanIDFor[T any](name ...string) BeanID

BeanIDFor returns a BeanID for the given type T.

type BeanProvider added in v1.3.0

type BeanProvider = gs_init.BeanProvider

type Condition added in v1.2.0

type Condition = gs.Condition

Condition represents a logical predicate that decides whether a bean or module should be activated.

func And added in v1.2.0

func And(conditions ...Condition) Condition

And combines multiple conditions using logical AND. The combined condition is satisfied only if ALL conditions are true.

Example:

// Activate only if production AND database configured
gs.And(
    gs.OnProperty("app.env").HavingValue("production"),
    gs.OnBean[*Database](),
)

func None added in v1.2.0

func None(conditions ...Condition) Condition

None returns a condition that is true if ALL provided conditions are false. It is equivalent to NOR (NOT OR) logic.

Example:

// Activate only if neither debug nor verbose is enabled
gs.None(gs.OnProperty("debug"), gs.OnProperty("verbose"))

func Not added in v1.2.0

func Not(c Condition) Condition

Not returns the logical negation of the given condition. It inverts the result: true becomes false, false becomes true.

Example:

// Activate bean only if debug mode is NOT enabled
gs.Not(gs.OnProperty("debug.enabled"))

func OnBean added in v1.2.0

func OnBean[T any](name ...string) Condition

OnBean requires that a bean of the given type (and optional name) exists. The condition is satisfied if at least one matching bean is found.

Example:

// Require a Logger bean to exist
gs.OnBean[*Logger]()

// Require a specific named DataSource bean
gs.OnBean[*DataSource]("primary")

func OnExpression added in v1.2.0

func OnExpression(expression string) Condition

OnExpression creates a condition from an expression. The expression is evaluated to determine if the condition is satisfied.

Example (future):

gs.OnExpression("${app.port} > 8080 && ${app.env} == 'prod'")

func OnFunc added in v1.2.0

func OnFunc(fn func(ctx ConditionContext) (bool, error)) Condition

OnFunc creates a Condition backed by the given function. This is the most flexible way to create custom conditions.

Example:

gs.OnFunc(func(ctx gs.ConditionContext) (bool, error) {
    val, ok := ctx.Prop("feature.enabled")
    return ok && val == "true", nil
})

func OnMissingBean added in v1.2.0

func OnMissingBean[T any](name ...string) Condition

OnMissingBean requires that no bean of the given type (and optional name) exists. The condition is satisfied if zero matching beans are found.

Example:

// Provide default logger only if none exists
gs.Provide(&DefaultLogger{}).Condition(gs.OnMissingBean[*Logger]())

func OnOnce added in v1.2.3

func OnOnce(conditions ...Condition) Condition

OnOnce wraps the given conditions so they are evaluated only once. Subsequent calls return the cached result without re-evaluation.

func OnSingleBean added in v1.2.0

func OnSingleBean[T any](name ...string) Condition

OnSingleBean requires that exactly one instance of the given bean type exists. The condition is satisfied if len(beans) == 1.

Example:

// Ensure only one Database connection exists
gs.OnSingleBean[*Database]()

func Or added in v1.2.0

func Or(conditions ...Condition) Condition

Or combines multiple conditions using logical OR. The combined condition is satisfied if AT LEAST ONE condition is true.

Example:

// Activate if either dev OR test profile is active
gs.Or(gs.OnProperty("profile.dev"), gs.OnProperty("profile.test"))

type ConditionContext added in v1.2.3

type ConditionContext = gs.ConditionContext

ConditionContext provides the evaluation context for a Condition.

type Configuration added in v1.3.0

type Configuration = gs_bean.Configuration

type ContextProvider added in v1.3.0

type ContextProvider = gs_app.ContextProvider

type Dync added in v1.2.0

type Dync[T any] = gs_dync.Value[T]

Dync is a generic alias for a dynamic configuration value. Dync values are automatically updated when the underlying configuration changes.

type HttpServeMux added in v1.3.0

type HttpServeMux struct {
	http.Handler
}

HttpServeMux is a lightweight wrapper around an http.Handler, allowing the default http.ServeMux or a custom handler to be injected into the HTTP server.

type ModuleFunc added in v1.3.0

type ModuleFunc = gs_init.ModuleFunc

ModuleFunc defines the signature of a module function.

Use cases:

  • Auto-configuration modules (similar to Spring Boot starters)
  • Grouping related bean registrations
  • Conditional bean registration based on configuration

type PropertiesRefresher added in v1.3.0

type PropertiesRefresher = gs_app.PropertiesRefresher

type PropertyCondition added in v1.3.0

type PropertyCondition = gs_cond.PropertyCondition

PropertyCondition is a convenience wrapper for property-based conditions.

func OnProperty

func OnProperty(name string) PropertyCondition

OnProperty creates a property-based condition. It checks for the presence and/or value of a configuration property.

Example:

// Match if property exists
gs.OnProperty("app.name")

// Match if property has specific value
gs.OnProperty("app.env").HavingValue("production")

// Match if property is missing
gs.OnProperty("debug.mode").MatchIfMissing()

type ReadySignal added in v1.2.0

type ReadySignal = gs_app.ReadySignal

type Runner added in v1.2.0

type Runner = gs_app.Runner

type Server added in v1.2.0

type Server = gs_app.Server

type SimpleHttpServer added in v1.2.0

type SimpleHttpServer struct {
	// contains filtered or unexported fields
}

SimpleHttpServer wraps a standard http.Server to integrate it into the Go-Spring application lifecycle.

func NewSimpleHttpServer added in v1.2.0

func NewSimpleHttpServer(h *HttpServeMux, cfg SimpleHttpServerConfig) *SimpleHttpServer

NewSimpleHttpServer constructs a new SimpleHttpServer using the provided HTTP handler and configuration.

func (*SimpleHttpServer) Run added in v1.3.0

Run starts the HTTP server and blocks until it is stopped. It listens on the configured address immediately, but waits for the given ReadySignal before accepting traffic.

func (*SimpleHttpServer) Stop added in v1.3.0

func (s *SimpleHttpServer) Stop() error

Stop gracefully stops the HTTP server, allowing in-flight requests to complete.

type SimpleHttpServerConfig added in v1.2.4

type SimpleHttpServerConfig struct {
	// Address specifies the TCP address the server listens on.
	// Example: ":9090" (listen on all interfaces, port 9090).
	Address string `value:"${addr:=:9090}"`

	// ReadTimeout is the maximum duration for reading the entire
	// HTTP request, including the body.
	ReadTimeout time.Duration `value:"${readTimeout:=5s}"`

	// HeaderTimeout is the maximum duration for reading request headers.
	HeaderTimeout time.Duration `value:"${headerTimeout:=1s}"`

	// WriteTimeout is the maximum duration before timing out
	// an HTTP response write.
	WriteTimeout time.Duration `value:"${writeTimeout:=5s}"`

	// IdleTimeout is the maximum time to wait for the next request
	// when keep-alive connections are enabled.
	IdleTimeout time.Duration `value:"${idleTimeout:=60s}"`
}

SimpleHttpServerConfig holds configuration for SimpleHttpServer.

Directories

Path Synopsis
internal
gs
gs_arg
Package gs_arg provides implementations for argument resolution and binding used by the Go-Spring framework.
Package gs_arg provides implementations for argument resolution and binding used by the Go-Spring framework.
gs_bean
Package gs_bean provides core bean management for Go-Spring framework.
Package gs_bean provides core bean management for Go-Spring framework.
gs_cond
Package gs_cond provides a set of composable conditions used to control bean registration for Go-Spring framework.
Package gs_cond provides a set of composable conditions used to control bean registration for Go-Spring framework.
gs_conf
Package gs_conf provides a layered configuration system for Go-Spring applications.
Package gs_conf provides a layered configuration system for Go-Spring applications.
gs_dync
Package gs_dync provides dynamic configuration binding and refresh capabilities for Go-Spring applications.
Package gs_dync provides dynamic configuration binding and refresh capabilities for Go-Spring applications.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL