Я обычно использую следующий подход:
Определите синглтон-компонент, который будет содержать зависимость от фабрики:
public class MyService {
private final Provider<Book> bookFactory;
public MyService(Provider<Book> bookFactory) {
this.bookFactory = bookFactory;
}
public void doSomething() {
Book book = bookFactory.get();
book.setNumberOfReaders(numOfReaders); // this is a drawback, book is mutable, if we want to set runtime params (like numberOfReaders)
....
}
}
Теперь определите прототип для боба книги:
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Book book(...) {
return new Book(...);
}
@Bean // scope singleton by default
public MyService myService(Provider<Book> bookFactory) {
return new MyService(bookFactory);
}
}
Обратите внимание, что провайдер имеет тип "javax.inject.Provider", чтобы использовать id, import (например, в maven):
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
Spring может справиться с этим начиная с 4.x (я думаю, 4.1) без какой-либо дополнительной настройки
Конечно, этот подход устраняет необходимость внедрять контекст приложения на фабрику и вообще поддерживать фабрику
Один недостаток заключается в том, что он не позволяет строить объект с аргументами, эти аргументы должны быть указаны во время выполнения.
Существует также другой подход - генерация подкласса во время выполнения в сочетании с аннотацией @Lookup
, описанная здесь Здесь , но подход IMO Provider лучше.