java 如何修改spring容器中定义的bean
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1486779/
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 to modify beans defined in a spring container
提问by tangens
I have two xml files defining beans for the springframework (version 2.5.x):
我有两个 xml 文件为 springframework(版本 2.5.x)定义 bean:
containerBase.xml:
<beans>
<bean id="codebase" class="com.example.CodeBase">
<property name="sourceCodeLocations">
<list>
<value>src/handmade/productive</value>
</list>
</property>
</bean>
</beans>
... and
... 和
containerSpecial.xml:
<beans>
<import resource="containerBase.xml" />
</beans>
Now I want to adjust the property sourceCodeLocationsof bean codebasewithin containerSpecial.xml. I need to add a second value src/generated/productive.
现在我想调整财产sourceCodeLocationsbean的codebase范围内containerSpecial.xml。我需要添加第二个值src/generated/productive。
A simple approachis to override the definition of codebasein containerSpecial.xmland add both values, the one from containerBase.xmland the new one:
一种简单的方法是覆盖codebasein的定义containerSpecial.xml并添加两个值,一个来自containerBase.xml和新的值:
containerSpecial.xml:
<beans>
<import resource="containerBase.xml" />
<bean id="codebase" class="com.example.CodeBase">
<property name="sourceCodeLocations">
<list>
<value>src/handmade/productive</value>
<value>src/generated/productive</value>
</list>
</property>
</bean>
</beans>
Is there a way to extend the list without redefining the bean?
有没有办法在不重新定义 bean 的情况下扩展列表?
EDIT 2009-10-06:
编辑 2009-10-06:
The purpose of this is to have a shared standard container containerBasethat is used by a lot of different projects. Each project can override/extend some properties that are special for that project in its own containerSpecial. If the project doesn't override, it's using the defaults defined in containerBase.
这样做的目的是拥有一个可供containerBase许多不同项目使用的共享标准容器。每个项目都可以在自己的containerSpecial. 如果项目未覆盖,则使用containerBase.
采纳答案by Jason Gritman
You could use a BeanFactoryPostProcessorto change the bean's metadata before the Spring container instantiates the CodeBase bean. For example:
您可以使用BeanFactoryPostProcessor在 Spring 容器实例化 CodeBase bean 之前更改 bean 的元数据。例如:
public class CodebaseOverrider implements BeanFactoryPostProcessor {
private List<String> sourceCodeLocations;
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
CodeBase codebase = (CodeBase)beanFactory.getBean("codebase");
if (sourceCodeLocations != null)
{
codebase.setSourceCodeLocations(sourceCodeLocations);
}
}
public void setSourceCodeLocations(List<String> sourceCodeLocations) {
this.sourceCodeLocations = sourceCodeLocations;
}
}
Then in contextSpecial.xml:
然后在 contextSpecial.xml 中:
<beans>
<import resource="context1.xml" />
<bean class="com.example.CodebaseOverrider">
<property name="sourceCodeLocations">
<list>
<value>src/handmade/productive</value>
<value>src/generated/productive</value>
</list>
</property>
</bean>
</beans>
回答by kdubb
Yes. A bean definition can have a "parent" attribute that references a parent bean definition. The new "child" definition inherits most of the properties of the parent and any of those properties can be overridden.
是的。bean 定义可以具有引用父 bean 定义的“parent”属性。新的“子”定义继承了父项的大部分属性,并且可以覆盖任何这些属性。
See Bean Definition Inheritance
Also you can use Collection Mergingto merge the list property definition from the parent and child bean definitions. This way you can specify some list items in the parent bean definition and add more items to it in the child bean definition.
您还可以使用集合合并来合并来自父 bean 和子 bean 定义的列表属性定义。通过这种方式,您可以在父 bean 定义中指定一些列表项,并在子 bean 定义中向其添加更多项。
回答by Pablojim
3 approaches:
3种方法:
Simple: have two lists defaultSourceCodeLocations and additionalSourceCodeLocations and have your accessor methods check both of these (or combine them). I've seen this done in some frameworks - a default list of handlers is populated then additional user created ones are added...
More complicated but keeps the original class clean: You could then create a CodeBaseModifier class. This would have a init-method to alter an injected instance of the bean.
<bean id="codebaseModifier" class="com.example.CodeBase" init-method="populateCodeBase"> <property name="sourceCodeLocations" ref="codebase"/> <property name="additionalSourceCodeLocations"> <list> <value>src/handmade/productive</value> </list> </property> </bean>
简单:有两个列表 defaultSourceCodeLocations 和 additionalSourceCodeLocations 并让您的访问器方法检查这两个(或组合它们)。我已经在某些框架中看到了这一点 - 填充了默认的处理程序列表,然后添加了其他用户创建的处理程序...
更复杂但保持原始类干净:然后您可以创建一个 CodeBaseModifier 类。这将有一个 init 方法来改变注入的 bean 实例。
<bean id="codebaseModifier" class="com.example.CodeBase" init-method="populateCodeBase"> <property name="sourceCodeLocations" ref="codebase"/> <property name="additionalSourceCodeLocations"> <list> <value>src/handmade/productive</value> </list> </property> </bean>
If you wanted to make this really generic you could make a bean modifier that would do this by reflection. Be careful of the ordering if use this approach. Dependent beans of CodeBase would have to make sure this class was instantiated first (with depends on)
如果你想让它真正通用,你可以制作一个通过反射来做到这一点的 bean 修改器。如果使用这种方法,请注意顺序。CodeBase 的依赖 bean 必须确保首先实例化这个类(依赖于)
3 A variation on 2... Instead of directly creating a CodeBase class instead create a factory that returns a populated bean. This factory could then be configured with Spring in a similar fashion to 2. Have a defaultSourceCodeLocations and additionalSourceCodeLocations
3 2 的变体...与其直接创建 CodeBase 类,不如创建一个返回填充 bean 的工厂。然后可以以与 2 类似的方式使用 Spring 配置该工厂。有一个 defaultSourceCodeLocations 和 additionalSourceCodeLocations
Unless you need a lot of extensible properties I would go with option 1.
除非你需要很多可扩展的属性,否则我会选择选项 1。
回答by jon077
Is there a way to define the list in a properties or other configuration before hand?
有没有办法事先在属性或其他配置中定义列表?
It seems like the app configuration and wiring are tightly coupled. From my experience, if it is hard to do something in Spring, likely there is a different easier way to do it.
应用程序配置和布线似乎是紧密耦合的。根据我的经验,如果在 Spring 中做某事很困难,可能有另一种更简单的方法来做。
回答by Thrawn
In Spring 3.0, you can specify merge="true" on the 'list' tag. See http://forum.springsource.org/archive/index.php/t-97501.htmlfor details.
在 Spring 3.0 中,您可以在 'list' 标签上指定 merge="true"。有关详细信息,请参阅http://forum.springsource.org/archive/index.php/t-97501.html。

