Skip to main content
Winter Boot uses a pure attribute-driven IoC container. Every class you annotate with a stereotype — #[Service], #[Component], or #[Configuration] — is discovered during namespace scanning at startup, instantiated once as a singleton, and registered in the bean registry. Dependencies between beans are expressed with #[Autowired] on class properties, and the container resolves and injects them automatically so you never call new on a managed object. All stereotype attributes live in the dev\winterframework\stereotype\ namespace.

#[Service]

#[Service] marks a concrete class as a service-layer component. It is a class-level attribute and cannot be placed on abstract classes. The container registers the bean either by its class name (unnamed) or by a string identifier (named).
Two beans cannot share the same name. A name collision at startup throws an exception before any request is served.

Impl suffix — automatic interface aliasing

When a class whose name ends with the exact suffix Impl (case-sensitive) is registered, the container also registers it under every interface it implements. This lets you depend on an interface type without knowing the concrete class.
Impl suffix aliasing
Without the Impl suffix the interface alias is not created:
No Impl suffix — interface lookup fails
If multiple *Impl classes implement the same interface, calling beanByClass(Interface::class) throws NoUniqueBeanDefinitionException. Disambiguate with beanByName("beanName"), beanByNameClass("beanName", Interface::class), #[Autowired("beanName")], or #[Qualifier] at the injection point.

#[Component]

#[Component] is semantically identical to #[Service] — the container treats both the same way — but is conventionally used for infrastructure, utility, or cross-cutting classes that don’t belong to a specific service layer.
The same Impl-suffix aliasing rule applies to #[Component] beans, making it easy to wire infrastructure components by interface.

#[Configuration] and #[Bean]

#[Configuration] marks a class as a factory configuration class. Methods inside it annotated with #[Bean] act as factory methods: the container calls them once, caches the returned object, and registers it as a managed bean. #[Bean] is a method-level attribute. The factory method must:
  • belong to a #[Configuration] class
  • declare a return type (no union types, no built-in scalar types)
  • not be a constructor or destructor
The initMethod is called right after the bean is constructed. destroyMethod is registered and called when the process exits.
#[Bean] factory methods are not subject to the Impl-suffix aliasing rule. They are registered only under their declared return type.

#[Autowired]

#[Autowired] is a property-level attribute. When the container instantiates a bean it inspects every property tagged with #[Autowired] and resolves them from the bean registry. The property must have a declared, non-union, non-built-in type. Both concrete class types and interfaces (when aliased via Impl) can be autowired.
Autowired by type
To inject a named bean rather than resolving by type, pass the name as the first argument:
Autowired by name

#[Qualifier]

#[Qualifier] is a parameter-level attribute used to disambiguate when multiple beans of the same type exist. Apply it to constructor or method parameters in scenarios where #[Autowired] alone cannot pick the right bean.
Qualifier on constructor parameters

#[Value]

#[Value] is a property-level attribute that injects a scalar value from application.yml. The expression must use the ${key.path} syntax — otherwise startup throws a TypeError. The property must be typed with a scalar built-in type (string, int, float, bool). You can pass an optional default as the second argument.

ApplicationContext — programmatic bean lookup

ApplicationContext is itself injectable via #[Autowired] in any bean. It gives you full programmatic access to the container and configuration properties at runtime.
DynamicServiceLocator.php

Bean lookup methods

mixed
Retrieve a bean by its fully-qualified class or interface name.
mixed
Retrieve a named bean by its registered string identifier.
mixed
Retrieve a named bean and verify it against a class or interface type.
bool
Check whether a bean is registered for the given class or interface.
bool
Check whether a named bean is registered in the container.

Property access methods

mixed
Generic property read from the loaded configuration.
string
Read a configuration property as a string.
bool
Read a configuration property as a boolean.
int
Read a configuration property as an integer.
float
Read a configuration property as a float.
array
Return all loaded configuration properties as an associative array.
mixed
Overwrite a property value at runtime (does not persist to disk).
Property access examples

Metadata methods

Context metadata