如何在Spring应用程序上下文中扩展已经定义的列表和映射?

2022-09-03 00:58:23

想象一下具有不同阶段的暂存应用程序上下文。我们从早期阶段开始,定义必要的基础设施。xml 应用程序上下文按顺序加载。

拆分这些文件的原因是扩展/插件机制。

阶段 01 - 默认配置.xml

我们准备并使用 id 声明地图,以便以后使用数据对其进行增强。exampleMapping

<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="[...]">

  <util:map id="exampleMapping" />
</beans>

阶段 02 - 自定义配置.xml(可选)

我们配置并添加一个条目。exampleMapping

<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="[...]">

  <util:map id="exampleMapping">
    <entry key="theKey" value="theValue" />
  </util:map>
</beans>

阶段 03-利用配置.xml(强制)

使用定义的映射,无论它是自定义配置的还是仍然是空的声明映射。exampleMapping

<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="[...]">

    <bean id="exampleService" class="com.stackoverflow.example.ExampleService">
       <property name="mapping" ref="exampleMapping" />
    </bean>
</beans>

这里的问题是,在第一阶段之后,无法向地图添加条目。Spring 会引发一个异常,指出 id 所在的映射已存在。如果我们省略第一阶段,则地图未声明,第三阶段无法解析,这也会产生异常。exampleMappingexampleMappingexampleMapping

我该如何解决这个问题?我读了收藏合并(春季文档),但这没有帮助。是否可以在以后使用映射/列表之前向它们添加值?

谢谢!


答案 1

两者都具有此属性,用于合并两个列表。或者,您可以使用 调用已定义列表的 add 方法,以便以后添加额外的项。maplistmerge=true|falseMethodInvokingFactoryBean

让我们回顾一下您的示例。

1) 首先是 第二种情况。我没有定义你的方式,而是以不同的方式定义你的豆子。MethodInvokingFactoryBean

<bean class="java.util.HashMap" id="exampleMapping">
    <constructor-arg index="0">
        <map>
            <entry key="theKey" value="theValue"/>
        </map>
    </constructor-arg>
</bean>

<bean id="exampleService" class="com.stackoverflow.example.ExampleService">
    <property name="mapping" ref="exampleMapping"/>
</bean>

在另一个应用程序内容文件中,可以执行以下操作来扩展映射。

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="exampleMapping"/>
    <property name="targetMethod" value="putAll"/>
    <property name="arguments">
        <list>
            <map id="exampleMapping">
            <entry key="theKey2" value="theValue2"/>
            <entry key="theKey3" value="theValue3"/>
            <map>
        </list>
    </property>
</bean>

2)现在是第一种情况。对于这个,我刚刚在页面上找到了一些东西 http://forum.springsource.org/showthread.php?t=53358

<bean id="commonData" class="A">
    <property name="map">
        <util:map>
            <entry key="1" value="1"/>
        </util:map>
    </property>
</bean>
<bean id="data" class="A" parent="commonData">
    <property name="map">
        <util:map merge="true">
            <entry key="2" value="2"/>
        </util:map>
    </property>
</bean>

希望它有帮助。


答案 2

你可以定义第二个定义是在一个单独的文件中,你用来将一个文件导入另一个文件,但这是一种脆弱的方法,很容易被破坏。exampleMapping<import resource="..."/>

我建议采取更稳健的策略。将 替换为类,该类又包含并管理映射:exampleMappingRegistry

public MappingRegistry<K,V> {

   private final Map<K,V> mappings = new HashMap<K,V>();

   public void addMapping(K key, V value) {
      mappings.put(key, value);
   }

   public Map<K,V> getMappings() {
      return Collections.unmodifiableMap(mappings);
   }
}

然后,编写一个向注册表注册映射的类:

public class MappingRegistrar<K,V> {

   private final MappingRegistry<K,V> registry;

   private K key;
   private V value;

   @Autowired
   public MappingRegistrar(MappingRegistry<K,V> registry) {
      this.registry = registry;
   }

   public void setKey(K key) {
      this.key = key;
   }

   public void setValue(V value) {
      this.value = value;
   }

   @PostConstruct
   public void registerMapping() {
      registry.addMapping(key, value);
   }
}

您的配置将变为如下所示:

<bean id="mappingRegistry" class="com.xyz.MappingRegistry"/>

<bean id="mappingA" class="com.xyz.MappingRegistrar" p:key="keyA" p:value="valueA"/>
<bean id="mappingB" class="com.xyz.MappingRegistrar" p:key="keyB" p:value="valueB"/>
<bean id="mappingC" class="com.xyz.MappingRegistrar" p:key="keyC" p:value="valueC"/>

这些映射现在可以以您认为合适的任何方式分散在整个配置中,并且它们将自组装。 然后注入 并相应地提取映射。ExampleServcieMappingRegistry

这比您已经拥有的工作要多一些,但它更灵活,更不容易出错。如果您正在尝试构建某种可扩展的框架,这尤其有价值;你想对人们如何使用它施加更少的限制。


推荐