將原型範圍的豆子注入單例

容器建立一個單獨的 bean 並僅將協作者注入其中一次。當單例 bean 具有原型範圍的協作者時,這不是期望的行為,因為每次通過訪問器訪問時都應注入原型範圍的 bean。

這個問題有幾種解決方案:

  1. 使用查詢方法注入
  2. 通過 javax.inject.Provider 檢索原型範圍的 bean
  3. 通過 org.springframework.beans.factory.ObjectFactory(相當於#2,但具有特定於 Spring 的類)檢索原型範圍的 bean
  4. 通過實現 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 注入單例)。