將原型範圍的豆子注入單例
容器建立一個單獨的 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 注入單例)。