将原型范围的豆子注入单例
容器创建一个单独的 bean 并仅将协作者注入其中一次。当单例 bean 具有原型范围的协作者时,这不是期望的行为,因为每次通过访问器访问时都应注入原型范围的 bean。
这个问题有几种解决方案:
- 使用查找方法注入
- 通过
javax.inject.Provider
检索原型范围的 bean - 通过
org.springframework.beans.factory.ObjectFactory
(相当于#2,但具有特定于 Spring 的类)检索原型范围的 bean - 通过实现
ApplicationContextAware
接口使单个 bean 容器有用
通常不鼓励使用方法#3 和#4,因为它们强烈地将应用程序绑定到 Spring 框架。因此,在这个例子中没有涉及它们。
通过 XML 配置和抽象方法注入查找方法
Java 类
public class Window {
}
public abstract class WindowGenerator {
public Window generateWindow() {
Window window = createNewWindow(); // new instance for each call
...
}
protected abstract Window createNewWindow(); // lookup method
}
XML
<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>
<bean id="windowGenerator" class="somepackage.WindowGenerator">
<lookup-method name="createNewWindow" bean="window"/>
</bean>
通过 Java 配置和 @Component 注入查找方法
Java 类
public class Window {
}
@Component
public class WindowGenerator {
public Window generateWindow() {
Window window = createNewWindow(); // new instance for each call
...
}
@Lookup
protected Window createNewWindow() {
throw new UnsupportedOperationException();
}
}
Java 配置
@Configuration
@ComponentScan("somepackage") // package where WindowGenerator is located
public class MyConfiguration {
@Bean
@Lazy
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Window window() {
return new Window();
}
}
通过 Java 配置手动查找方法注入
Java 类
public class Window {
}
public abstract class WindowGenerator {
public Window generateWindow() {
Window window = createNewWindow(); // new instance for each call
...
}
protected abstract Window createNewWindow(); // lookup method
}
Java 配置
@Configuration
public class MyConfiguration {
@Bean
@Lazy
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Window window() {
return new Window();
}
@Bean
public WindowGenerator windowGenerator(){
return new WindowGenerator() {
@Override
protected Window createNewWindow(){
return window();
}
};
}
}
通过 javax.inject.Provider
将原型范围的豆注入单例
Java 类
public class Window {
}
public class WindowGenerator {
private final Provider<Window> windowProvider;
public WindowGenerator(final Provider<Window> windowProvider) {
this.windowProvider = windowProvider;
}
public Window generateWindow() {
Window window = windowProvider.get(); // new instance for each call
...
}
}
XML
<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>
<bean id="windowGenerator" class="somepackage.WindowGenerator">
<constructor-arg>
<bean class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
<property name="targetBeanName" value="window"/>
</bean>
</constructor-arg>
</bean>
同样的方法也可以用于其他范围(例如,将请求范围的 bean 注入单例)。