@Bean
@Bean() marks a method whose return value is a bean.
Why
Use it when a class cannot carry @Component itself: it comes from another package, or its constructor needs arguments that are not beans. Use it also when creating the object takes code.
The method lives in a @Configuration class, or in a @Component class ("lite" mode), or is static. Its parameters are injected like constructor parameters, including @Value settings and @Qualifier selections.
Rules:
- The bean name is the method name, unless
name:is given. - The bean type is what the method returns. When the returned expression has a more specific static type than the declared return type, that type is used.
DataSource dataSource() => PooledDataSource()is registered asPooledDataSourceand all its supertypes. - A method declared
T?may returnnull. The bean then exists by name, but is absent for lookups and injection by type. - A function type or record type can be a bean too. It is injected by that exact type, into single injection points only.
- At shutdown the container calls a public no-argument
close(),shutdown()ordispose()of the declared return type, if there is one.destroyMethod: ''turns that off.
Example
import 'package:spring_core_dart/spring_core_dart.dart';
class Pool {
Pool(this.size);
final int size;
void open() {}
void close() {}
}
class Client {
void close() {}
}
abstract interface class Executor {
void execute(void Function() task);
}
class SingleExecutor implements Executor {
@override
void execute(void Function() task) => task();
}
@Configuration()
class AppConfig {
// The size comes from the configuration, 4 when unset. open() runs
// once the pool is created; close() runs at shutdown (inferred).
// The bean can be found as 'mainPool' or 'pool'.
@Bean(name: 'mainPool', aliases: ['pool'], initMethod: 'open')
Pool pool(@Value(r'${pool.size:4}') int size) => Pool(size);
// This client is shared with code outside the container, so the
// container must not close it.
@Bean(destroyMethod: '')
static Client client() => Client();
// A second executor that must not get in the way of the main one:
// it is injected only where @Qualifier('audit') asks for it.
@Bean(defaultCandidate: false)
@Qualifier('audit')
Executor auditExecutor() => SingleExecutor();
}
Parameters
| Name | Type | Default | Meaning |
|---|---|---|---|
name |
String? |
null |
The bean name. null gives the method name. |
aliases |
List<String> |
[] |
More names the bean can be found under. |
initMethod |
String? |
null |
A no-argument method of the bean, called once it is injected. For objects you cannot annotate with @PostConstruct. |
destroyMethod |
String? |
Bean.inferMethod |
A no-argument method called when the context closes. The default infers close, shutdown or dispose. An empty string calls nothing. |
autowireCandidate |
bool |
true |
Whether the bean can be injected by type at all. With false it is still found by name. |
defaultCandidate |
bool |
true |
Whether the bean is injected where only its type is asked for. With false it is injected only where a qualifier (@Qualifier, the bean name or an alias) selects it. |
In Spring (Java)
@Configuration
class AppConfig {
@Bean(name = {"mainPool", "pool"}, initMethod = "open")
Pool pool(@Value("${pool.size:4}") int size) { return new Pool(size); }
@Bean(destroyMethod = "")
static Client client() { return new Client(); }
@Bean(defaultCandidate = false)
@Qualifier("audit")
Executor auditExecutor() { return Executors.newSingleThreadExecutor(); }
}
Differences that matter:
- Spring puts aliases in the
namearray after the first name. Here they are a separatealiaseslist. - Spring knows only the declared return type of a
@Beanmethod until the bean is created. Here the generator reads the method body, sogetBean<PooledDataSource>()and conditions on the bean type work before creation. - Spring infers
closeandshutdownas destroy methods. Heredisposeis inferred too, because it is the Dart idiom.