【问题标题】:Using placeholders in definition of PropertySourcesPlaceholderConfigurer在 PropertySourcesPlaceholderConfigurer 的定义中使用占位符
【发布时间】:2013-03-06 09:04:22
【问题描述】:

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

此启动信息由两部分组成:

1) 配置服务的 URI - 这是作为系统属性传递给 Mule 并被正确获取

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

尝试的解决方案:

1) 单个重写的 PropertyPlaceholderConfigurer(我知道,我知道),其中包含所有决定编码的逻辑

2) 多个不同顺序的 PropertyPlaceholderConfigurer(一个处理文件系统属性,一个处理 Web 服务属性)

3) 实现 Order 的自定义 BeanFactoryPostProcessor

4) 将 WebServicePropertySource 定义为 @Configuration 并使用 @PropertySource 显式引用外部文件(失败,因为在需要 WebServicePropertySource 来解析占位符时未初始化环境)

5) 单个 PropertySourcesPlaceholderConfigurer 带有一个自定义 PropertySource 来处理 Web 服务属性和 ResourcePropertySources 来处理文件系统属性

所有这些方法(除了 4 种)都失败了,因为我在 PropertySourcesPlaceholderConfigurer/PropertyPlaceholderConfigurer 的定义中使用了占位符 - 占位符未解析并且传递给 Web 服务的领域是 $ {catalogue-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。记录已确认 propertySources 列表在运行时包含 14 个元素(Web 服务属性源加上 13 个资源)

我很确定这段摘录简洁地说明了我正在尝试做的事情,但如果没有,请询​​问更多详细信息。我的问题的症结在于 Web 服务帮助程序中的 ${catalogue-service-realm} 占位符没有从类路径上的属性文件中保存的信息中解析出来。

在我看来,这就像先有鸡还是先有蛋的问题,也必须有一个简单的解决方案 - 我只是不知道它是什么,所以非常感谢任何帮助或指点 :-)

亲切的问候, 马特

【问题讨论】:

    标签: web-services spring configuration mule


    【解决方案1】:

    您是否考虑过使用Spring Profiles

    您可以在 mule here 中找到有关如何利用它们的简短示例

    【讨论】:

    • 感谢您的快速响应!在检查 \@Configuration 方法时,我确实查看了 Spring Profiles,但它们看起来与我的问题正交 - 我认为如果可以在编译时枚举服务实例,配置文件将起作用。因为我们可能一天有 20 个服务实例需要独特的配置,而下一天需要 100 个,这并不实际。如果您可以在 \@Profile 中使用占位符,也可能会起作用 - 例如\@Profile("${catalogue-service-realm}") 但我想我会遇到同样的问题
    【解决方案2】:

    Java Configuration API 支持multi-tenant configuration

    要与 Spring 集成,您可以使用here 发布的一些解决方案,或者仅利用 SpEL,即:@Property("expression")

    【讨论】:

    • 有趣 - 这实际上会起作用,因为它会使用 Spring 配置以外的其他东西来执行引导部分,所以当 Spring PropertySourcesPlaceholderConfigurer 开始使用 Web 服务时,它已经被某些东西配置了别的。但是,这将:1)需要手动解析占位符 2)涉及在每个服务/应用程序中具有 2 种不同的配置机制(加上依赖项)。因此,我忽略了它,而赞成(恕我直言)答案中概述的稍微不那么丑陋的方法。
    【解决方案3】:

    我的问题的症结在于 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>
    

    【讨论】:

      猜你喜欢
      • 2015-08-01
      • 2013-12-12
      • 2021-01-12
      • 1970-01-01
      • 1970-01-01
      • 2013-05-12
      • 1970-01-01
      • 2015-07-29
      • 2011-09-05
      相关资源
      最近更新 更多