背景 我正在使用Mule将大量Web服务部署到多个Mule实例。我使用Spring来配置服务,这一切都与文件系统上属性文件中的配置完美配合。为了简化这种设置的管理,我想将所有配置移动到Web服务,只保留文件系统上的最小引导信息。
此引导信息由两部分组成:
1)配置服务的URI - 它作为系统属性传递给Mule并正确选取
2)配置域 - 允许服务实例向配置服务标识自身的附加标识符(例如,在服务器dev-2上运行的目录服务的实例)。此部分无法编码到Spring配置中(例如,通过将configRealm设置为catalog-service),因为每个配置服务可能正在向给定服务的多个实例(例如,目录服务)提供配置信息
尝试解决方案:
1)单个被覆盖的PropertyPlaceholderConfigurer(我知道,我知道),其中所有逻辑都决定在
中编码2)具有不同订单的多个PropertyPlaceholderConfigurers(一个用于处理文件系统属性,一个用于处理Web服务属性)
3)实现Order
的自定义BeanFactoryPostProcessor4)将WebServicePropertySource定义为@Configuration并使用@PropertySource显式引用外部文件(由于环境未在解析占位符时需要WebServicePropertySource进行初始化,因此失败)
5)单个PropertySourcesPlaceholderConfigurer,其中包含用于处理Web服务属性的自定义PropertySource和用于处理文件系统属性的RespourcePropertySources
所有这些方法(除了4个)都因为我在PropertySourcesPlaceholderConfigurer / PropertyPlaceholderConfigurer的定义中使用占位符这一事实 - 占位符未解析且传递给Web服务的领域是$ {catalog-service-realm}或类似的。
我知道我可以通过使用系统属性来定义配置域来完成这项工作,但由于在Mule实例中可能会部署很多服务,因此这很难看,并且需要重新启动服务器才能进行任何更改。
在下面的代码中,我将示例限制为最新的解决方案(上面的5),因为它使用最新的Spring 3.1 API。
摘自mule-config.xml:
<spring:bean id="configServiceHelper" class="config.client.GetConfigurationServiceHelper">
<spring:property name="configRealm" value="${catalogue-service-realm}"/>
<spring:property name="configServiceWsdlUrl" value="${configuration.service.url}"/>
</spring:bean>
<spring:bean id="webServicePropertySource" class="config.client.WebServicePropertySource">
<spring:constructor-arg name="name" value="web-service-property-source"/>
<spring:constructor-arg name="helper" ref="configServiceHelper"/>
</spring:bean>
<spring:bean id="propertySources" class="config.client.DefaultPropertySources">
<spring:property name="propertySources">
<spring:list>
<spring:ref bean="webServicePropertySource"/>
</spring:list>
</spring:property>
</spring:bean>
<spring:bean class="config.client.LocationPropertySourcesPlaceholderConfigurer">
<spring:property name="propertySources" ref="propertySources"/>
<spring:property name="locations">
<spring:list>
<spring:value>classpath*:spring/config/*.properties</spring:value>
<spring:value>classpath:catalogue-service.properties</spring:value>
<spring:value>classpath:catalogue-service-override.properties</spring:value>
</spring:list>
</spring:property>
</spring:bean>
请注意: config.client.LocationPropertySourcesPlaceholderConfigurer的行为与默认的PropertySourcesPLaceholderConfigurer的不同之处在于,如果设置了propertySources,则不会丢弃位置,而是将它们添加到propertySources。 Logging已确认propertySources列表在运行时包含14个元素(Web服务属性源加上13个资源)
我很确定这段摘录简明扼要地说明了我要做的事情,但如果没有,请询问更多细节。我的问题的关键在于,Web服务帮助程序中的$ {catalog-service-realm}占位符未从类路径上的属性文件中保存的信息中解析。
这对我来说就像一个鸡和蛋的问题,必须有一个简单的解决方案 - 我只是不知道它是什么所以任何帮助或指针将非常感激: - )
亲切的问候, 马特
答案 0 :(得分:0)
您是否考虑过使用Spring Profiles?
您可以在mule here
中找到有关如何利用它们的简短示例答案 1 :(得分:0)
Java Configuration API支持multi-tenant configuration。
要与Spring集成,您可以使用here发布的一些解决方案,或者只使用SpEL,即:@Property("expression")
。
答案 2 :(得分:0)
我的问题的关键是没有解析PropertySourcesPlaceholderConfigurer bean定义中的占位符。
我通过显式地手动解析有问题的configRealm属性定义中的占位符来解决这个问题。它不是很优雅,但它确实避免了使用上面Victor Romero提出的附加配置库的需要。
下面注释了Spring配置。
<!-- configRealm moved to webServicePropertySource to prevent
the need to pollute service client with Spring PropertyResolver -->
<spring:bean id="configServiceHelper" class="config.client.GetConfigurationServiceHelper">
<spring:property name="configServiceWsdlUrl" value="${configuration.service.url}"/>
</spring:bean>
<!-- WebServicePropertySource now contains configRealm and a PropertyResolver to use
to resolve the placeholder -->
<spring:bean id="webServicePropertySource" class="config.client.WebServicePropertySource">
<spring:constructor-arg name="name" value="web-service-property-source"/>
<spring:constructor-arg name="helper" ref="configServiceHelper"/>
<spring:constructor-arg name="realm" value="${bisac_genre_service.config_realm}"/>
<spring:constructor-arg name="resolver" ref="propertyResolver"/>
</spring:bean>
<!-- New class to wrap a bunch of resources into a PropertySource -->
<spring:bean id="resourcePropertySource" class="config.client.ResourceAggregationPropertySource">
<spring:constructor-arg name="name" value="resource-property-source"/>
<spring:constructor-arg name="resources">
<spring:list>
<spring:value>classpath*:spring/config/*.properties</spring:value>
<spring:value>classpath:genre-service.properties</spring:value>
<spring:value>classpath:genre-service-override.properties</spring:value>
</spring:list>
</spring:constructor-arg>
</spring:bean>
<!-- Standard PropertySourcesPropertyResolver defined to just use the
classpath resources for resolution -->
<spring:bean id="propertyResolver" class="org.springframework.core.env.PropertySourcesPropertyResolver">
<spring:constructor-arg ref="resourcePropertySources"/>
</spring:bean>
<!-- PropertySources consisting of just the filesystem resources -->
<spring:bean id="resourcePropertySources" class="config.client.DefaultPropertySources">
<spring:property name="propertySources">
<spring:list>
<spring:ref bean="resourcePropertySource"/>
</spring:list>
</spring:property>
</spring:bean>
<!-- PropertySources consisting of the web service source plus
the filesystem resources -->
<spring:bean id="allPropertySources" class="config.client.DefaultPropertySources">
<spring:property name="propertySources">
<spring:list>
<spring:ref bean="resourcePropertySource"/>
<spring:ref bean="webServicePropertySource"/>
</spring:list>
</spring:property>
</spring:bean>
<!-- Vanilla Spring PropertySourcesPlaceholderConfigurer using ALL PropertySources -->
<spring:bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<spring:property name="propertySources" ref="allPropertySources"/>
</spring:bean>