你能帮我摆脱ApplicationContext
吗?
我有一个工厂,所以所有的书籍实例都是春天的豆子。我认为制作所有豆子是一个很好的决定。
@Component
public class BookFactoryImpl implements BookFactory {
private final ApplicationContext applicationContext;
@Autowired
public BookFactoryImpl(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Book createBook(String name) {
return applicationContext.getBean(Book.class, name);
}
}
这是一个带有@Bean
method的配置类,用于实例化Book
类的新实例:
@Configuration
@ComponentScan({"factory"})
public class AppConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Lazy
public Book book(String name) {
return Book.builder().name(name).build();
}
}
这是我的Book
实体类:
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@EqualsAndHashCode
@ToString
@Builder
public class Book {
@Id
@GeneratedValue
private int id;
@Basic(fetch = FetchType.LAZY)
private String name;
}
我有更多的想法 - 用BookFactoryImpl
注释@Configuration
并在其中移动@Bean
方法但在这种情况下,我的工厂将变成具有破坏生命周期的@Configuration
类。
您如何看待,实施工厂的最佳方式是什么?如何减少ApplicationContext
等外部依赖性?
或者用@Configuration
方法制作所有工厂作为@Bean
类很好,你觉得怎么样?
不,在Spring管理的应用程序中创建每个类都不是一个好主意。
JPA实体通常应该由Spring托管bean中的代码实例化。
我通常使用以下方法:
定义将包含对工厂的依赖的单例bean:
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)
....
}
}
现在定义book bean的原型:
@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);
}
}
注意,Provider的类型为“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
注释相结合,其描述的Here但IMO Provider方法更好。