4

我的 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 从单个文件中获取属性,并适当地映射名称?

4

1 回答 1

6

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>

使用上述配置和一个合并的.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
于 2012-06-29T18:38:11.313 回答