我们可以为XML中提到的相同bean ID重复名称吗? 如果没有,那么我们如何在Spring中覆盖bean?
答案 0 :(得分:62)
任何给定的Spring上下文对于任何给定的id或名称只能有一个bean。对于XML id
属性,这由架构验证强制执行。在name
属性的情况下,这由Spring的逻辑强制执行。
但是,如果上下文是由两个不同的XML描述符文件构造的,并且两个文件都使用id
,那么将会“覆盖”另一个文件。确切的行为取决于文件在上下文加载时的顺序。
尽管有可能,但不建议这样做。它容易出错并且很脆弱,如果你更改了一个而不是另一个的ID,你将无法获得Spring的帮助。
答案 1 :(得分:11)
我将补充一点,如果你的需要只是覆盖你的bean使用的属性,id方法也像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>
然后你的bean“myBeanId”将使用一个元素的“myList”属性进行实例化,该元素为6。
答案 2 :(得分:8)
来自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>
这就是你在找什么?
答案 3 :(得分:8)
不确定这是否正是您所需要的,但我们正在使用配置文件来定义我们正在运行的环境以及每个环境的特定bean,所以它就是这样的:
<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>
因此,在这种情况下,如果我没有定义配置文件或者我将其定义为“DEV”,myBean将为其名称参数获取“overrideValue”。但如果我将配置文件设置为“CI”,“UAT”或“PROD”,它将获得“originalValue”作为值。
答案 4 :(得分:3)
bean重写的另一种方法是通过别名。这个blog article解释了这种方法。
答案 5 :(得分:2)
其他帖子中未提及的另一个好方法是使用PropertyOverrideConfigurer,以防您只想覆盖某些bean的 属性 。
例如,如果要在另一个xml配置中覆盖用于测试的数据源(即使用内存数据库),则只需在新配置中使用3x^2 + 3x + 4
,并在{0}包含<context:property-override ..."/>
文件以.properties
格式覆盖主要道具的键值。
<强>应用mainConfig.xml:强>
beanName.property=newvalue
<强>应用testConfig.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" />
<强> beanOverride.properties:强>
<import resource="classpath:path/to/file/application-mainConfig.xml"/>
<!-- override bean props -->
<context:property-override location="classpath:path/to/file/beanOverride.properties"/>
答案 6 :(得分: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>
答案 7 :(得分:0)
从Spring 3.0开始,您可以使用@Primary
注释。根据文档:
指示当多个时应优先考虑Bean 候选人有资格自动装配单值依赖项。如果 候选者之间确实存在一个“主要” bean,它将是 自动接线值。此注释在语义上等同于 元素在Spring XML中的主要属性。
您应该像这样在Bean定义上使用它:
@Bean
@Primary
public ExampleBean exampleBean(@Autowired EntityManager em) {
return new ExampleBeanImpl(em);
}
或类似这样:
@Primary
@Service
public class ExampleService implements BaseServive {
}
答案 8 :(得分:0)
问题更多地是关于XML的,但是由于注释在当今越来越流行,因此我将通过示例展示它的工作原理。
让我们创建类Foo
:
public class Foo {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
和两个配置文件(您不能创建一个):
@Configuration
public class Configuration1 {
@Bean
public Foo foo() {
Foo foo = new Foo();
foo.setName("configuration1");
return foo;
}
}
和
@Configuration
public class Configuration2 {
@Bean
public Foo foo() {
Foo foo = new Foo();
foo.setName("configuration2");
return foo;
}
}
让我们看看调用foo.getName()
时会发生什么:
@SpringBootApplication
public class OverridingBeanDefinitionsApplication {
public static void main(String[] args) {
SpringApplication.run(OverridingBeanDefinitionsApplication.class, args);
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(
Configuration1.class, Configuration2.class);
Foo foo = applicationContext.getBean(Foo.class);
System.out.println(foo.getName());
}
}
在本示例中,的结果是:configuration2
。
Spring容器获取所有配置元数据源,并在这些源中合并bean定义。在此示例中,有两个@Bean
。将它们送入ApplicationContext
的顺序决定。您可以翻转new AnnotationConfigApplicationContext(Configuration2.class, Configuration1.class);
,结果将为configuration1
。