FactoryBean
A FactoryBean<T> is a bean whose job is to make another object: the container hands out what getObject() returns, not the factory itself.
Why
Use it when building an object takes logic that a library wants to keep behind one bean: a client set up from many settings, a proxy, an object from a builder API. In application code a @Bean method is usually simpler.
How the container treats it:
- Looking the bean up by name, or by the product type, returns the product.
- The factory itself is available under
&beanName, or by its own type. - The product of a singleton factory is created once and cached. With
isSingletonreturningfalse,getObject()runs on every lookup. - Products get
postProcessAfterInitializationapplied, but no injection and no init callbacks. The factory itself is an ordinary bean: it is injected and initialized. - What
getObject()throws becomes aBeanCreationExceptionof the bean.
The generator recognizes a @Component class that extends FactoryBean<T>, and a @Bean method that returns one. It records T as the product type.
SmartFactoryBean<T> tells the container more about the product:
isEagerInit: create the product at startup, not on first use;isPrototype: everygetObject()call returns an independent instance;supportsTypeandgetObjectForType: serve products of more types thanT, as in Spring 7.
Example
import 'package:spring_core_dart/spring_core_dart.dart';
class HttpClient {
HttpClient(this.baseUrl, this.timeout);
final String baseUrl;
final Duration timeout;
}
// Every bean that injects HttpClient gets one configured from properties.
@Component()
class HttpClientFactory extends FactoryBean<HttpClient> {
HttpClientFactory(
@Value(r'${api.url}') this.baseUrl,
@Value(r'${api.timeout-seconds:10}') this.timeoutSeconds,
);
final String baseUrl;
final int timeoutSeconds;
@override
HttpClient getObject() =>
HttpClient(baseUrl, Duration(seconds: timeoutSeconds));
}
@Service()
class Catalog {
Catalog(this.client); // the product, not the factory
final HttpClient client;
}
class Connection {
static Connection open() => Connection();
}
// The connection is opened at startup, not on first use.
@Component()
class ConnectionFactory extends SmartFactoryBean<Connection> {
@override
Connection getObject() => Connection.open();
@override
bool get isEagerInit => true;
}
final client = context.getBean<HttpClient>(); // the product
final same = context.getBeanByName('httpClientFactory'); // the product
final factory = context.getBeanByName('&httpClientFactory'); // the factory
Members
FactoryBean<T>:
| Member | Default | Meaning |
|---|---|---|
T getObject() |
required | Creates or returns the product. |
bool get isSingleton |
true |
Whether getObject() returns the same instance every time; the container then caches it. |
Type get objectType |
T |
The product type. Used for a factory added with registerSingleton. |
SmartFactoryBean<T> adds:
| Member | Default | Meaning |
|---|---|---|
bool get isPrototype |
false |
Whether every getObject() call returns an independent instance. |
bool get isEagerInit |
false |
Whether the product of a non-lazy singleton factory is created at startup. |
bool supportsType(Type type) |
objectType or Object |
Whether the factory serves a product for lookups by type. |
Object? getObjectForType(Type type) |
getObject() when supported |
The product for a lookup by type. null fails the lookup. |
BeanFactory.factoryBeanPrefix is the & prefix.
In Spring (Java)
@Component
class HttpClientFactory implements FactoryBean<HttpClient> {
@Override
public HttpClient getObject() { return HttpClient.newHttpClient(); }
@Override
public Class<?> getObjectType() { return HttpClient.class; }
}
HttpClient client = context.getBean(HttpClient.class);
Object factory = context.getBean("&httpClientFactory");
Differences that matter:
FactoryBeanis an abstract class: extend it.getObjectType()is theobjectTypegetter and defaults toT.- The product type is known at build time from the type argument, so a lookup by product type never needs to create the factory first.
See also
- @Bean
- @Component
- BeanPostProcessor
- ConfigurableListableBeanFactory (
isFactoryBean) - ApplicationContext (
getBeanByName)