Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在Spring应用程序上下文中扩展已经定义的列表和映射?_Java_Spring_Dependency Injection - Fatal编程技术网

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

Java 如何在Spring应用程序上下文中扩展已经定义的列表和映射?,java,spring,dependency-injection,Java,Spring,Dependency Injection,设想一个具有不同阶段的分阶段应用程序上下文。我们从早期阶段开始定义必要的基础设施。xml应用程序上下文按顺序加载 拆分这些文件的原因是扩展/插件机制 Stage 01 default configuration.xml 我们准备并声明id为exampleMapping的映射,以便稍后使用数据增强它们 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/

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

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

Stage 01 default configuration.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>
阶段03使用configuration.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>

这里的问题是,在第一阶段之后,无法向
exampleMapping
映射添加条目。Spring抛出一个异常,即id为
exampleMapping
的映射已经存在。如果我们省略了第一阶段,则映射未声明,第三阶段无法解析
exampleMapping
,这也会产生异常

我如何解决这个问题?我读了(spring文档),但这没有帮助。是否可以在以后使用地图/列表之前将值添加到地图/列表中


谢谢大家!

map和
list
都将此属性命名为
merge=true | false
,用于合并两个列表。或者,您可以使用
MethodInvokingFactoryBean
调用已定义列表的add方法,以便稍后添加额外的项

让我们看一下你的例子

1) 第一个场景是使用
MethodInvokingFactoryBean
的第二个场景。我没有定义您的方式,而是对您的bean进行了稍微不同的定义

<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) 现在是第一种情况。对于这一个,我在第页上找到了一些东西


希望对您有所帮助。

您可以定义
示例Mapping
是第二个定义,它位于一个单独的文件中,您可以使用
将一个文件导入到另一个文件中,但这是一种脆弱的方法,很容易损坏

我建议采取更稳健的策略。将
示例映射
替换为
注册表
类,该类依次包含并管理映射:

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);
   }
}
公共映射注册表{
私有最终映射映射=新HashMap();
公共void addMapping(K键,V值){
映射。put(键、值);
}
公共映射getMappings(){
返回集合。不可修改映射(映射);
}
}
然后,编写一个向注册表注册映射的类:

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);
   }
}
公共类映射注册器{
私人最终地图登记处;
私钥;
私人价值;
@自动连线
公共MappingRegistrator(MappingRegistry注册表){
this.registry=注册表;
}
公共无效设置密钥(K密钥){
this.key=key;
}
公共无效设置值(V值){
这个值=值;
}
@施工后
公共无效注册表映射(){
addMapping(键、值);
}
}
您的配置将如下所示:

<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"/>

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


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

您所说的“第一阶段之后无法通过条目进行增强”是什么意思?您能提供一个简单的示例吗?不幸的是,我没有让它运行。我更新了答案并给出了两个选项的示例。我认为第一个场景对于这种方法来说不是一个很好的设计,对我来说听起来很脏。第二个问题有点模糊,我认为编写skaffmann提到的注册表将是最好的。谢谢你的回答和解释!实际上也是一样,你只需要让
mappingregister
为你自己做,而不是自己调用put方法,不管怎样,我个人不喜欢为这类事情编写代码,如果我可以声明性地做的话。你是对的,但如果有可能避免反射和使用API的不稳定方式,我会投票支持这种编码方式。在这种情况下,#putAll()方法不会改变,但是使用另一个API可能不稳定,你不认为吗?我已经使用这种机制为特殊类型的过滤器/值提供程序提供了一个可扩展的特性。我认为这会带来很大的开销,对于列表/地图,有一种更简单的方法来实现这一点。显然不是。我会像你建议的那样实施它。也许我们将来会看到这样的spring功能?谢谢大家!@codevour:我不认为这是过分的,我认为这是一个很好的设计。在我看来,它比使用裸体地图更健壮、更明确、更可读。你可能是对的,这可能是一种非常通用的方法,bean也可能是匿名的。想一想,这很适合我的方法。再次感谢你。
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"/>