@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
thisskips 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.
Example
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)
@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@Lazyinjection points at startup.
See also
- ObjectProvider
- @ComponentScan (
lazyInit) - @Scope
- BeanFactoryPostProcessor: make a library's bean lazy
- AOP