简体   繁体   中英

Is there a way to re-use a <util:list> in spring configuration file?

I have a bunch of rules to be injected into a set of classes, something like below:

<bean id="rule1" class="com.vikdor.rules.Rule1" />
<bean id="rule2" class="com.vikdor.rules.Rule2" />
<bean id="rule3" class="com.vikdor.rules.Rule3" />
<bean id="rule4" class="com.vikdor.rules.Rule4" />
<bean id="rule5" class="com.vikdor.rules.Rule5" />

<util:list id="commonRules">
    <ref bean="rule1" />
    <ref bean="rule3" />
    <ref bean="rule5" />
</util:list>

<util:list id="normalInvRules">
   <!-- Include common rules -->
   <ref bean="rule4" />
</util:list>

<util:list id="prepaidInvRules">
   <!-- Include common rules -->
   <ref bean="rule2" />
</util:list>

How can I include the common rules list in the lists corresponding to normalInvRules and prepaidInvRules ?

The number of rules (eg rule1, rule2 etc.,) are more and the number groups (normalInvRules, prepaidInvRules etc.,) are also more. So, I am wondering if there is a way to avoid repeating the common rules and just list only the specific ones and include the reference to the common list.

There is a feature called 'collection merging' that does exactly this. See section 3.3.3.4.1. "Collection merging" in the Spring documentation or the 2008 blog post (with an example) that I wrote on the subject .

I like the approach suggested by @GreyBeardedGeek, just want to throw in a few more suggestions:

a. Doing it using @Configuration with the base rules list in xml:

@Configuration
@ImportResource("classpath:/baseconfig.xml")
public static class RulesConfiguration{
    @Resource List<Rule> commonRules;

    @Bean
    public List<Rule> normalInvRules(){
        List<Rule> rules = new ArrayList<Rule>();
        rules.addAll(commonRules);
        rules.add(new Rule());
        return rules;
    }
}

b. Using a custom factory bean, responsible for extending a list:

class ListExpandingFactoryBean<T> implements FactoryBean<List<T>>{

    private List<T> baseList;
    private List<T> extendedList;

    @Override
    public List<T> getObject() throws Exception {
        List<T> consolidatedList = new ArrayList<T>();
        consolidatedList.addAll(baseList);
        consolidatedList.addAll(extendedList);
        return consolidatedList;
    }

    @Override
    public Class<?> getObjectType() {
        return List.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
    public void setBaseList(List<T> baseList) {
        this.baseList = baseList;
    }

    public List<T> getExtendedList() {
        return extendedList;
    }

    public void setExtendedList(List<T> extendedList) {
        this.extendedList = extendedList;
    }

}

and using it this way:

<bean name="normalInvRules" class="ListExpandingFactoryBean" p:baseList-ref="commonRules">
    <property name="extendedList">
        <list>
            <ref bean="bean4"/>
        </list>
    </property>
</bean>

Thanks for the responses. This is how I have finally addressed it using Collection Merging :

<bean id="rule1" class="com.krovi.rules.Rule1" />
<bean id="rule2" class="com.krovi.rules.Rule2" />
<bean id="rule3" class="com.krovi.rules.Rule3" />
<bean id="rule4" class="com.krovi.rules.Rule4" />
<bean id="rule5" class="com.krovi.rules.Rule5" />

<bean id="commonList"
    class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
        <list>
            <ref bean="rule1" />
            <ref bean="rule2" />
            <ref bean="rule3" />
        </list>
    </property>
</bean>
<bean id="firstExecutorRules" parent="commonList"
    class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
        <list merge="true">
            <ref bean="rule4" />
        </list>
    </property>
</bean>
<bean id="secondExecutorRules" parent="commonList"
    class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
        <list merge="true">
            <ref bean="rule5" />
        </list>
    </property>
</bean>

You may create a class with common rules and auto wire them in other rules? Would n't that work?

You can take the same approach using XML config and inject it using ref attribute as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM