Java 如何在Spring应用程序上下文中扩展已经定义的列表和映射?
设想一个具有不同阶段的分阶段应用程序上下文。我们从早期阶段开始定义必要的基础设施。xml应用程序上下文按顺序加载 拆分这些文件的原因是扩展/插件机制 Stage 01 default configuration.xml 我们准备并声明id为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/
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"/>