[英]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.