合并Spring引用的多个属性文件

时间:2012-06-21 10:15:44

标签: java spring properties

My Spring配置如下所示:

<jee:remote-slsb id="ejb1"
    jndi-name="org.example.Ejb1"
    business-interface="org.example.Ejb1"
    environment-ref="ejb1Properties">
</jee:remote-slsb>
<util:properties id="ejb1Properties" location="classpath:ejb1.properties"/>

<jee:remote-slsb id="ejb2"
    jndi-name="org.example.Ejb2"
    business-interface="org.example.Ejb2"
    environment-ref="ejb2Properties">
</jee:remote-slsb>
<util:properties id="ejb2Properties" location="classpath:ejb2.properties"/>

...因为两个EJB可能使用不同的JNDI URL,不同的上下文工厂和身份验证凭据。 ejb1.properties和ejb2.properties具有相同名称的属性,具有不同的值:

ejb1.properties:
  java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
  java.naming.provider.url=t3://example1:7101
  java.naming.security.principal=id1
  java.naming.security.credential=foo

ejb2.properties:
  java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
  java.naming.provider.url=t3://example2:7101
  java.naming.security.principal=id2
  java.naming.security.credential=bar

但是,我希望我的用户可以维护一个属性文件,而不是两个。

显然,编写一个从核心属性文件生成ejb1.properties和ejb2.properties的启动脚本很容易。但有没有办法让Spring从单个文件获取属性,适当地映射名称?

1 个答案:

答案 0 :(得分:5)

AFAIK,Spring中没有任何东西可以处理你的情况。但是,一个直接的解决方案是扩展PropertiesFactoryBean并覆盖mergeProperties()方法。以下是基于名称前缀过滤属性条目的扩展示例:

public class FilteringPropertiesFactoryBean extends PropertiesFactoryBean {

    private String namePrefix;

    @Override
    protected Properties mergeProperties() throws IOException {
        Properties unfilteredProperties = super.mergeProperties();

        Properties filteredProperties = new Properties();

        // iterator over keys
        // discard entries whose key doesn't start with prefix
        for (Object key : unfilteredProperties.keySet()) {
            String name = key.toString();

            // trim the property name by removing the target prefix.
            String trimmedName = trimName(name);
            if (trimmedName != null) {
                // add the property to the filtered collection
                String value = unfilteredProperties.getProperty(name);
                filteredProperties.setProperty(trimmedName, value);
            }
        }

        return filteredProperties;
    }

    public void setNamePrefix(String value) {
        this.namePrefix = value;
    }

    private String trimName(String name) {
        // does name start with the prefix and is the name longer than the prefix
        if (name.startsWith(namePrefix) && name.length() > namePrefix.length()) {
            return name.substring(namePrefix.length());
        }
        return null;
    }

}

配置工厂bean将类似于:

<bean id="ejb1Properties" class="example.FilteringPropertiesFactoryBean">
  <property name="location" value="classpath:merged.properties"/>
  <property name="namePrefix" value="ejb1."/>
</bean>

使用上面的配置和merged.properties文件包含:

ejb1.java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
ejb1.java.naming.provider.url=t3://example1:7101
ejb1.java.naming.security.principal=id1
ejb1.java.naming.security.credential=foo

ejb2.java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
ejb2.java.naming.provider.url=t3://example2:7101
ejb2.java.naming.security.principal=id2
ejb2.java.naming.security.credential=bar

FilteringPropertiesFactoryBean#mergeProperties()返回的结果属性是(注意前缀从最终属性名称中删除):

java.naming.factory.initial = weblogic.jndi.WLInitialContextFactory
java.naming.provider.url = t3://example1:7101
java.naming.security.principal = id1
java.naming.security.credential = foo