Java 如何覆盖 Spring bean 定义但仍然引用被覆盖的 bean?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2437497/
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
How do I override a Spring bean definition yet still reference the overridden bean?
提问by Kevin
I'm attempting to implement a delegate Service provider by overriding the bean definition for the original service with my delegate Service. However, as the name would imply, the delegate Service needs a reference to the original service to delegate calls to.
我试图通过用我的委托服务覆盖原始服务的 bean 定义来实现委托服务提供者。但是,顾名思义,委托服务需要对原始服务的引用来委托调用。
I'm having trouble figuring out how to override the bean definition while using the original bean def without running into a circular reference issue.
我无法弄清楚如何在使用原始 bean def 时覆盖 bean 定义而不会遇到循环引用问题。
For example:
例如:
<!-- Original service def in spring-context.xml -->
<bean id="service" class="com.mycompany.Service"/>
<!-- Overridden definition in spring-plugin-context.xml -->
<bean id="service" class="com.mycompany.DelegatedService"/>
<constructor-arg ref="service"/>
</bean>
Is this possible?
这可能吗?
采纳答案by skaffman
The short answer to your question is that you cannot have two bean definitions with the same name. If you try, one will hide the other, and only one definition will be usable.
对您的问题的简短回答是,您不能有两个同名的 bean 定义。如果您尝试,一个将隐藏另一个,并且只有一个定义可用。
Your question's example seems to suggest that you're trying to wrap the original service
bean in a proxy object, with the wrapper performing some before-and-after work around calls to the service. One way to achieve this, without defining two service
beans, and without modifying the original service
bean, is to use a Spring AutoProxyCreator
, probably a BeanNameAutoProxyCreator
.
您的问题示例似乎表明您正尝试将原始service
bean包装在代理对象中,包装器围绕对服务的调用执行一些前后工作。实现这一目标的一种方式,不限定两个service
豆,没有修改原始service
豆腐,是用一个春天AutoProxyCreator
,大概BeanNameAutoProxyCreator
。
This allows you to list a bean (or beans) that are to be automatically proxied. You specify the interceptors you want to be applied to invocations on the target bean. You would implement these interceptors to do the work you need to do.
这允许您列出要自动代理的 bean(或 bean)。您指定要应用于目标 bean 调用的拦截器。您将实现这些拦截器来完成您需要做的工作。
Spring would automatically create a delegating proxy for you, which would have the bean id service
as before, but with your additional functionality.
Spring 会自动为您创建一个委托代理,它会service
像以前一样具有 bean id ,但具有您的附加功能。
回答by saugata
You can create proxies and interceptors. So now the bean named service
will become a proxy to the original service
which needs to be renamed to something else. So the changes will be limited to the Spring XML only and not be propagated to your java code.
您可以创建代理和拦截器。所以现在命名的 beanservice
将成为原始的代理,service
它需要重命名为其他东西。因此,更改将仅限于 Spring XML,不会传播到您的 Java 代码。
<bean id="personTarget" class="com.mycompany.PersonImpl">
<property name="name"><value>Tony</value></property>
<property name="age"><value>51</value></property>
</bean>
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
<property name="someProperty"><value>Custom string property value</value></property>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>
<bean id="person"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>com.mycompany.Person</value></property>
<property name="target"><ref local="personTarget"/></property>
<property name="interceptorNames">
<list>
<value>myAdvisor</value>
<value>debugInterceptor</value>
</list>
</property>
</bean>
回答by krosenvold
It sounds like you're trying to reinvent spring-AOP. Please consider using spring-AOP for this.
听起来您正在尝试重新发明 spring-AOP。请考虑为此使用 spring-AOP。
It's possible to programatically change the name of the existing service and create a new bean with the old name. The autoproxying-code inside spring framework does this and you could have a look at that. A quick code search for AutoProxy* in the spring framework should get you there.
可以通过编程方式更改现有服务的名称并使用旧名称创建新 bean。spring 框架中的 autoproxying-code 就是这样做的,你可以看看那个。在 spring 框架中对AutoProxy* 进行快速代码搜索应该会让您到达那里。
Alternately if you control the client sites (the consumers), you could add a qualifier to your wrapper, and use qualifiers to coerce the proper implementations to the consumers. The the wrapper could use the unqualified implemementation to get access to the original. (It might also be possible to retro-mount a qualifier to the original implementation by adding another bean definition for service with a qualifier in xml code that you control, haven't tried this but it should work)
或者,如果您控制客户端站点(消费者),您可以向您的包装器添加一个限定符,并使用限定符将正确的实现强制给消费者。包装器可以使用不合格的实现来访问原始文件。(也可以通过在您控制的 xml 代码中添加另一个带有限定符的服务 bean 定义,将限定符重新安装到原始实现,尚未尝试过,但它应该可以工作)
回答by Oded Peer
Use the "parent" attribute of the "ref" element with a parent container.
You can find a detailed example in Spring documentation: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-ref-element
将“ref”元素的“parent”属性与父容器一起使用。
您可以在 Spring 文档中找到详细示例:http: //static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-ref-element
回答by Solubris
Have written a blog post on how to do this nicely: http://www.solubris.com/blog/overriding_spring_context_for_testing
写了一篇关于如何很好地做到这一点的博客文章:http: //www.solubris.com/blog/overriding_spring_context_for_testing
Using wildcard context definitions means you don't need to use imports.
使用通配符上下文定义意味着您不需要使用导入。
Parent doesn't work when you want to redefine the same bean with the same id.
当您想重新定义具有相同 id 的同一个 bean 时,Parent 不起作用。