Java Spring 原型 bean 与单例 bean 和依赖注入相结合。是否有仅配置的方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/829463/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring prototype beans in combination with singleton beans and dependency injection. Is there an approach that is configuration only?
提问by Yaneeve
I have a singleton bean which needs for each call of a function to return a reference to a different (new) prototype 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. Code sample will follow...
我有一个单例 bean,每次调用函数都需要返回对不同(新)原型 bean 的引用。我能想到的唯一方法是通过调用 getBean() 方法以编程方式从 BeanFactory/ApplicatioContext 中检索一个新的原型 bean 实例。代码示例将遵循...
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");
}
....
}
采纳答案by dfa
take a look at Method Injection
看看方法注入
回答by shrini1000
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). 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.
使用方法注入会使单例 bean 类难以进行单元测试(您需要创建一个子类来实现提供依赖项的方法)。此外,它的可重用性较低,因为您无法直接实例化它,因此如果您不使用 Spring 并想使用此类,则需要子类化并提供 bean 返回方法。
A better approach IMHO is to use a proxy, a prototype target source and a prototype target bean, as follows. Such a singleton-bean class is easily unit-testable and better reusable.
恕我直言,更好的方法是使用代理、原型目标源和原型目标 bean,如下所示。这样的单例 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, (e.g. 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();
}
}
回答by Christopher Yang
From Spring 3.0, we can use <aop:scoped-proxy>
for dependency injection of the proper scope. 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 3.0 开始,我们可以使用<aop:scoped-proxy>
适当范围的依赖注入。在幕后,Spring 注入代理对象并负责找到正确的范围上下文,可以是原型、会话或请求等。请参阅此处的官方文档。
And to make life easier, Spring has also introduced proxyMode attribute for @Scope, so we are not limited to XML declarations only. For example:
为了让生活更轻松,Spring 还为 @Scope 引入了 proxyMode 属性,因此我们不仅限于 XML 声明。例如:
@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. Also, make sure equals() and hashCode() in the proxied class use access methods rather than directly accessing class variables.
确保清楚地记录注入的 bean 是一个代理,以警告其他人 getClass() 和强制转换可能不会产生预期的结果。此外,确保代理类中的 equals() 和 hashCode() 使用访问方法而不是直接访问类变量。