如何修改spring容器中定义的bean

时间:2009-09-28 12:35:22

标签: java spring ioc-container

我有两个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>

...和

containerSpecial.xml:
<beans>
    <import resource="containerBase.xml" />
</beans>

现在我想在sourceCodeLocations中调整bean codebase的属性containerSpecial.xml。我需要添加第二个值src/generated/productive

一种简单的方法是覆盖codebasecontainerSpecial.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>

有没有办法扩展列表而不重新定义bean?

编辑2009-10-06:

这样做的目的是拥有一个由许多不同项目使用的共享标准容器containerBase。每个项目都可以在自己的containerSpecial中覆盖/扩展该项目特有的一些属性。如果项目未覆盖,则使用containerBase中定义的默认值。

5 个答案:

答案 0 :(得分:8)

在Spring容器实例化Code​​Base bean之前,您可以使用BeanFactoryPostProcessor来更改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;
    }

}

然后在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>

答案 1 :(得分:3)

是。 bean定义可以具有引用父bean定义的“父”属性。新的“子”定义继承了父级的大多数属性,并且可以覆盖任何这些属性。

请参阅Bean Definition Inheritance

此外,您可以使用Collection Merging合并父和子bean定义中的列表属性定义。这样,您可以在父bean定义中指定一些列表项,并在子bean定义中为其添加更多项。

答案 2 :(得分:1)

3种方法:

  1. 简单:有两个列表defaultSourceCodeLocations和additionalSourceCodeLocations,并让您的访问者方法检查这两个(或组合它们)。我已经在一些框架中看到了这一点 - 填充了一个默认的处理程序列表,然后添加了其他用户创建的处理程序......

  2. 更复杂但保持原始类干净:然后您可以创建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>
    
  3. 如果你想让它变得非常通用,你可以制作一个通过反射来做到这一点的bean修饰符。如果使用这种方法,请注意订购。 CodeBase的依赖bean必须确保首先实例化该类(依赖于)

    3 2的变体...而不是直接创建CodeBase类而是创建一个返回填充bean的工厂。然后可以使用类似于2的方式将此工厂配置为2.具有defaultSourceCodeLocations和additionalSourceCodeLocations

    除非你需要很多可扩展的属性,否则我会选择选项1.

答案 3 :(得分:1)

有没有办法在手工定义属性或其他配置中的列表?

似乎应用配置和布线紧密耦合。根据我的经验,如果在Spring中很难做某事,可能会有一种更简单的方法。

答案 4 :(得分:1)

在Spring 3.0中,您可以指定merge =&#34; true&#34;在&#39;列表&#39;标签。有关详细信息,请参阅http://forum.springsource.org/archive/index.php/t-97501.html