将原型范围的豆子注入单例

容器创建一个单独的 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 注入单例)。