
# 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](bean.md) 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 `isSingleton` returning `false`, `getObject()` runs on every lookup.
- Products get `postProcessAfterInitialization` applied, but no injection and no init callbacks. The factory itself is an ordinary bean: it is injected and initialized.
- What `getObject()` throws becomes a `BeanCreationException` of 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`: every `getObject()` call returns an independent instance;
- `supportsType` and `getObjectForType`: serve products of more types than `T`, as in Spring 7.

## Example

```dart
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;
}
```

```dart
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)

```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:

- `FactoryBean` is an abstract class: extend it. `getObjectType()` is the `objectType` getter and defaults to `T`.
- 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](bean.md)
- [@Component](component.md)
- [BeanPostProcessor](bean-post-processor.md)
- [ConfigurableListableBeanFactory](configurable-listable-bean-factory.md) (`isFactoryBean`)
- [ApplicationContext](application-context.md) (`getBeanByName`)
