
# @Lazy

`@Lazy()` delays the creation of a bean, or of what an injection point receives, until it is first used.

## Why

Singletons are created at startup. That shows configuration errors early, but it also creates beans that many runs never need. `@Lazy()` has two uses.

**On a bean** (a class, a `@Bean` method, or a configuration class for all its `@Bean` methods): the singleton is created on the first lookup or injection instead of at startup. Use it for expensive beans that are rarely used, such as a report generator. `@Lazy(false)` makes one bean eager where its configuration class or the scan (`lazyInit: true`) would make it lazy.

**On an injection point** (a constructor parameter, a field, a setter): a generated proxy is injected instead of the bean. The proxy finds the bean on every call. This helps in two cases:

- to break a dependency cycle between two beans;
- to let a bean call itself through its AOP proxy, so that advice such as caching applies. A call through `this` skips the advice.

Even when lazy, the bean must exist and be unique. `refresh()` checks that at startup.

Limits on an injection point: the type must be implementable from generated code (an interface, or a class without private members, not generic), and the point must not be nullable. Otherwise use [ObjectProvider](object-provider.md).

## Example

```dart
import 'package:spring_core_dart/spring_core_dart.dart';

// Created on the first getBean or injection, not at startup.
@Component()
@Lazy()
class ReportGenerator {
  String render() => 'report';
}

abstract interface class Books {
  String find(String isbn);
  List<String> findAll(List<String> isbns);
}

// Calls through _self go through the proxy, so advice on find()
// (caching, timing) applies to each call.
@Service()
class BookService implements Books {
  BookService(@Lazy() this._self);
  final Books _self;

  @override
  String find(String isbn) => 'Book $isbn';

  @override
  List<String> findAll(List<String> isbns) =>
      [for (final isbn in isbns) _self.find(isbn)];
}

class PdfExporter {
  List<int> export(String text) => text.codeUnits;
}

// Every @Bean method of this class is lazy, except clock().
@Configuration()
@Lazy()
class ToolsConfig {
  @Bean()
  PdfExporter pdfExporter() => PdfExporter();

  @Bean()
  @Lazy(false)
  DateTime Function() clock() => DateTime.now;
}
```

## Parameters

| Name | Type | Default | Meaning |
|---|---|---|---|
| `value` (positional) | `bool` | `true` | Whether the bean or the injection point is lazy. |

## In Spring (Java)

```java
@Component
@Lazy
class ReportGenerator { ... }

@Service
class BookService {
  @Lazy @Autowired private BookService self;
}
```

Differences that matter:

- Spring creates the lazy-resolution proxy at run time. Here the generator writes it, hence the limits on the type.
- In Spring a lazy bean that is missing or ambiguous fails on first use. Here `refresh()` checks lazy beans and `@Lazy` injection points at startup.

## See also

- [ObjectProvider](object-provider.md)
- [@ComponentScan](component-scan.md) (`lazyInit`)
- [@Scope](scope.md)
- [BeanFactoryPostProcessor](bean-factory-post-processor.md): make a library's bean lazy
- [AOP](../aop/index.md)
