简体   繁体   English

Spring原型bean与单例bean和依赖注入相结合。有一种方法只是配置吗?

[英]Spring prototype beans in combination with singleton beans and dependency injection. Is there an approach that is configuration only?

I have a singleton bean which needs for each call of a function to return a reference to a different (new) prototype bean. 我有一个单例bean,它需要每次调用一个函数来返回对不同(新)原型bean的引用。 The only way that I can think of doing this is to programmatically retrieve a new prototype bean instance from the BeanFactory/ApplicatioContext by invoking its getBean() method. 我能想到的唯一方法是通过调用其getBean()方法以编程方式从BeanFactory / ApplicatioContext中检索新的原型bean实例。 Code sample will follow... 代码示例将遵循......

Is there a better way to do this? 有一个更好的方法吗? Only via configuration, hopefully? 只有通过配置,希望? (Personally, I doubt there is...) (我个人怀疑有...)

<bean id="protoBean" scope="prototype"
        class="com.blahblah.ProtoBean" />

<bean id="singletonBean"
        class="com.blahblah.SingletonBean" />

public class ProtoBean {

    ....
}

public class SingletonBean {

    private BeanFactory factory;

    public ProtoBean dispense() {
        return (ProtoBean) factory.getBean("protoBean");
    }

    ....
}

From Spring 3.0, we can use <aop:scoped-proxy> for dependency injection of the proper scope. 从Spring 3.0开始,我们可以使用<aop:scoped-proxy>来依赖注入适当的范围。 Behind the scene, Spring injects proxied objects and is responsible for finding the right scope context, may it be prototype, session or request etc. See the official documentations here . 在场景背后,Spring注入代理对象并负责查找正确的范围上下文,可能是原型,会话或请求等。请参阅此处的官方文档。

And to make life easier, Spring has also introduced proxyMode attribute for @Scope, so we are not limited to XML declarations only. 为了简化生活,Spring还为@Scope引入了proxyMode属性,因此我们不仅限于XML声明。 For example: 例如:

@Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)

Make sure to document clearly the injected bean is a proxy to warn others that getClass() and casting may not yield the expected result. 确保明确记录注入的bean是一个代理,以警告其他人getClass()和cast可能不会产生预期的结果。 Also, make sure equals() and hashCode() in the proxied class use access methods rather than directly accessing class variables. 此外,请确保代理类中的equals()和hashCode()使用访问方法,而不是直接访问类变量。

Using method injection makes the singleton-bean class difficult to unit-test (you need to create a subclass to implement the method which gives out the dependency). 使用方法注入会使singleton-bean类难以进行单元测试(您需要创建一个子类来实现赋予依赖关系的方法)。 Plus it's less reusable because you can't directly instantiate it, so if you're not using Spring and want to use this class, you'll need to subclass and provide the bean-returning method. 另外它不太可重用,因为你不能直接实例化它,所以如果你不使用Spring并想要使用这个类,你需要子类并提供bean返回方法。

A better approach IMHO is to use a proxy, a prototype target source and a prototype target bean, as follows. 一个更好的方法IMHO是使用代理,原型目标源和原型目标bean,如下所示。 Such a singleton-bean class is easily unit-testable and better reusable. 这种单例bean类很容易进行单元测试,可以更好地重复使用。

<bean id="targetPooledObject" class="pool.PooledObject" scope="prototype">
    <constructor-arg value="42" />
</bean>

<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
    <property name="targetBeanName" value="targetPooledObject" />
</bean>

<bean id="pooledObject" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource" ref="prototypeTargetSource" />           
</bean>

<bean id="poolConsumer" class="pool.PoolConsumer">
    <property name="pooledObject" ref="pooledObject" />
</bean>

Now we can inject pooledObject into a singleton bean ( poolConsumer as shown above), and for every method call that we make on that singleton bean, (eg every time we call poolConsumer.callPooledObjectMethod() which in turn calls pooledObject.foo() ) we get a new PooledObject bean. 现在我们可以将pooledObject注入一个单独的bean( poolConsumer如上所示),以及我们在该单例bean上进行的每个方法调用,(例如,每次调用poolConsumer.callPooledObjectMethod() ,然后调用pooledObject.foo() )我们得到一个新的PooledObject bean。

Following is the corresponding code: 以下是相应的代码:

public class PooledObject 
{
    private int x;

    public PooledObject(int x)
    {
        this.x = x;
    }

    public void foo()
    {
        System.out.println("foo called");
    }
}

public class PoolConsumer
{
    private PooledObject pooledObject;

    public PooledObject getPooledObject() 
    {
        return pooledObject;
    }

    public void setPooledObject(PooledObject pooledObject) 
    {
        this.pooledObject = pooledObject;
    }

    public void callPooledObjectMethod()
    {
        pooledObject.foo();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM