在PropertySourcesPlaceholderConfigurer的定义中使用占位符

时间:2013-03-06 09:04:22

标签: web-services spring configuration mule

背景 我正在使用Mule将大量Web服务部署到多个Mule实例。我使用Spring来配置服务,这一切都与文件系统上属性文件中的配置完美配合。为了简化这种设置的管理,我想将所有配置移动到Web服务,只保留文件系统上的最小引导信息。

此引导信息由两部分组成:

1)配置服务的URI - 它作为系统属性传递给Mule并正确选取

2)配置域 - 允许服务实例向配置服务标识自身的附加标识符(例如,在服务器dev-2上运行的目录服务的实例)。此部分无法编码到Spring配置中(例如,通过将configRealm设置为catalog-service),因为每个配置服务可能正在向给定服务的多个实例(例如,目录服务)提供配置信息

尝试解决方案:

1)单个被覆盖的PropertyPlaceholderConfigurer(我知道,我知道),其中所有逻辑都决定在

中编码

2)具有不同订单的多个PropertyPlaceholderConfigurers(一个用于处理文件系统属性,一个用于处理Web服务属性)

3)实现Order

的自定义BeanFactoryPostProcessor

4)将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}占位符未从类路径上的属性文件中保存的信息中解析。

这对我来说就像一个鸡和蛋的问题,必须有一个简单的解决方案 - 我只是不知道它是什么所以任何帮助或指针将非常感激: - )

亲切的问候, 马特

3 个答案:

答案 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>