2011-05-01 105 views
28

我们可以为XML中提及的同一个bean id重复名称吗? 如果不是,那么我们如何重写Spring中的bean?Spring的覆盖bean

+0

你能张贴一些示例xml以准确显示你的意思 – 2011-05-01 15:20:22

回答

50

任何给定的Spring上下文对于任何给定的id或名称只能有一个bean。在XML id属性的情况下,这由模式验证强制执行。在name属性的情况下,这是由Spring的逻辑强制执行的。

但是,如果上下文是由两个不同的XML描述符文件构成的,并且两个文件都使用了id,则会“覆盖”另一个文件。确切的行为取决于文件在被上下文加载时的排序。

所以虽然有可能,但并不推荐。这很容易出错并且很脆弱,如果你改变了一个而不是另一个的ID,你将不会从Spring那里得到任何帮助。

+0

如果它们处于相同的层次结构中有风险,但可以使用'profiles'(请参阅我的回答)更好地控制它。 – 2015-05-07 11:42:25

+1

有没有办法指示Spring在遇到任何具有相同ID的bean(即强调不允许覆盖)时抛出错误?这是用于'ServletContextHandler'的'contextConfigLocation'属性。 – 2015-08-28 20:22:30

7

official spring manual一个例子:

<bean id="inheritedTestBean" abstract="true" 
    class="org.springframework.beans.TestBean"> 
    <property name="name" value="parent"/> 
    <property name="age" value="1"/> 
</bean> 

<bean id="inheritsWithDifferentClass" 
     class="org.springframework.beans.DerivedTestBean" 
     parent="inheritedTestBean" init-method="initialize"> 
    <property name="name" value="override"/> 
    <!-- the age property value of 1 will be inherited from parent --> 
</bean> 

是你在找什么?

+0

看起来像官方的春季手册链接已损坏。 – Buchi 2012-02-01 10:11:50

+0

@Buchi感谢您的提示,修复了链接 – 2012-02-07 15:02:12

0

我们是否可以在其他xml中为其他参考e.x声明相同的bean id。

Servlet的Initialize.xml

<bean id="inheritedTestBean" class="org.springframework.beans.TestBean"> 
    <property name="name" value="parent"/> 
    <property name="age" value="1"/> 
</bean> 

其它XML(document.xml中)

<bean id="inheritedTestBean" class="org.springframework.beans.Document"> 
    <property name="name" value="document"/> 
    <property name="age" value="1"/> 
</bean> 
+0

春季是否允许?对不起,但我不清楚。 – Buchi 2012-02-01 10:07:41

+6

@Buchi是的,它是允许的。来自稍后顺序读取的文件中的Bean将完全覆盖先前的定义,该定义完全不会被实例化。 – mrembisz 2012-02-21 14:14:44

+0

你确定吗?你确定Spring在扫描结束时初始化/运行bean的构造函数吗?所以当我们将'inheritedtTestBean'注入另一个实施将被注入的bean?第一还是第二? – RMachnik 2014-07-24 21:32:31

10

我会补充一点,如果你需要的只是覆盖由您使用Bean的属性,标识办法也像skaffman解释:

在你的第一个被调用的XML配置文件中:

<bean id="myBeanId" class="com.blabla"> 
     <property name="myList" ref="myList"/> 
    </bean> 

    <util:list id="myList"> 
     <value>3</value> 
     <value>4</value> 
    </util:list> 

在你的第二个所谓的XML配置文件:

<util:list id="myList"> 
     <value>6</value> 
    </util:list> 

然后你豆“myBeanId”将是6

5

不知道一个元素的“myList中”属性被实例化,如果这正是你需要什么,但我们使用配置文件来定义我们是在和每个环境的具体豆运行的环境,所以它的类似的东西:

<bean name="myBean" class="myClass"> 
    <constructor-arg name="name" value="originalValue" /> 
</bean> 
<beans profile="DEV, default"> 
    <!-- Specific DEV configurations, also default if no profile defined --> 
    <bean name="myBean" class="myClass"> 
     <constructor-arg name="name" value="overrideValue" /> 
    </bean> 
</beans> 
<beans profile="CI, UAT"> 
    <!-- Specific CI/UAT configurations --> 
</beans> 
<beans profile="PROD"> 
    <!-- Specific PROD configurations --> 
</beans> 

因此,在这种情况下,如果I D不定义配置文件,或者如果我将其定义为“DEV”,则myBean将为其名称参数获得“overrideValue”。但是,如果我将配置文件设置为“CI”,“UAT”或“PROD”,它将获得“originalValue”作为值。

0

其他职位没有提到的另一个好方法是使用PropertyOverrideConfigurer如果你只是想覆盖性能一些豆类。

例如,如果您想覆盖测试的数据源(即,使用内存数据库)在另一个xml配置中,您只需在新配置中使用<context:property-override ..."/>,并使用包含格式为beanName.property=newvalue的键值的.properties文件覆盖主要道具。

应用mainConfig.xml:

<bean id="dataSource" 
    class="org.apache.commons.dbcp.BasicDataSource" 
    p:driverClassName="org.postgresql.Driver" 
    p:url="jdbc:postgresql://localhost:5432/MyAppDB" 
    p:username="myusername" 
    p:password="mypassword" 
    destroy-method="close" /> 

应用testConfig.xml:

<import resource="classpath:path/to/file/application-mainConfig.xml"/> 

<!-- override bean props --> 
<context:property-override location="classpath:path/to/file/beanOverride.properties"/> 

beanOverride.properties:

dataSource.driverClassName=org.h2.Driver 
dataSource.url=jdbc:h2:mem:MyTestDB