如何使用Spring框架从property-file获取值到Map?

Tim*_*kov 8 spring

现在我可以从属性文件中注入值:

@Value("${aaa.prop}")
public String someProp;
Run Code Online (Sandbox Code Playgroud)

但我想要更多......

例如,我有一些属性文件:

aaa.props=p1,p2,p3
aaa.props.p1=qwe
aaa.props.p2=asd
aaa.props.p3=zxc
Run Code Online (Sandbox Code Playgroud)

我肯定知道,它包含属性aaa.props,对其他属性一无所知.我希望使用这样的代码将这些属性映射到地图:

@Value ("${aaa.props}") 
public Map<String, String> someProps;
Run Code Online (Sandbox Code Playgroud)

结果someProps: {p1=qwe,p2=asd,p3=zxc}

Sea*_*oyd 5

我为你构建了一个通用方法:一个工厂bean,它通过过滤另一个地图来创建一个地图(毕竟,属性是一种地图).

这是工厂bean:

public class FilteredMapFactoryBean<V> extends
    AbstractFactoryBean<Map<String, V>>{

    private Map<String, V> input;

    /**
     * Set the input map.
     */
    public void setInput(final Map<String, V> input){
        this.input = input;
    }

    /**
     * Set the string by which key prefixes will be filtered.
     */
    public void setKeyFilterPrefix(final String keyFilterPrefix){
        this.entryFilter = new EntryFilter<String, V>(){

            @Override
            public boolean accept(final Entry<String, V> entry){
                return entry.getKey().startsWith(keyFilterPrefix);
            }
        };
    }

    public static interface EntryFilter<EK, EV> {

        boolean accept(Map.Entry<EK, EV> entry);
    }

    /**
     * If a prefix is not enough, you can supply a custom filter.
     */
    public void setEntryFilter(final EntryFilter<String, V> entryFilter){
        this.entryFilter = entryFilter;
    }

    private EntryFilter<String, V> entryFilter;

    /**
     * {@inheritDoc}
     */
    @Override
    public Class<?> getObjectType(){
        return Map.class;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Map<String, V> createInstance() throws Exception{
        final Map<String, V> map = new LinkedHashMap<String, V>();
        for(final Entry<String, V> entry : this.input.entrySet()){
            if(this.entryFilter == null || this.entryFilter.accept(entry)){
                map.put(entry.getKey(), entry.getValue());
            }
        }
        return map;
    }

}
Run Code Online (Sandbox Code Playgroud)

这是一个spring bean定义文件,其中包含一些示例用法:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- use System.getProperties() as input -->
    <bean class="spring.test.FilteredMapFactoryBean" id="javaMap">
        <property name="keyFilterPrefix" value="java." />
        <property name="input" value="#{T(java.lang.System).getProperties()}" />
    </bean>

    <!-- use custom properties as input -->
    <bean class="spring.test.FilteredMapFactoryBean" id="customMap">
        <property name="keyFilterPrefix" value="hello" />
        <property name="input">
            <props>
                <prop key="hello">Is it me you're looking for?</prop>
                <prop key="hello.again">Just called to say: hello.</prop>
                <prop key="hello.goodby">You say goodbye and I say hello</prop>
                <prop key="goodbye.blue.sky">Did-did-did-did-you hear the falling bombs?</prop>
                <prop key="goodbye.ruby.tuesday">Who could hang a name on you?</prop>
            </props>
        </property>
    </bean>

</beans>
Run Code Online (Sandbox Code Playgroud)

这是一个测试类:

public class Tester{

    @SuppressWarnings("unchecked")
    public static void main(final String[] args){
        final ApplicationContext context =
            new ClassPathXmlApplicationContext("classpath:spring/test/mapFactorybean.xml");

        final Map<String, String> javaMap =
            (Map<String, String>) context.getBean("javaMap");
        print("java.", javaMap);
        final Map<String, String> customMap =
            (Map<String, String>) context.getBean("customMap");
        print("hello.", customMap);

    }

    private static void print(final String prefix, final Map<String, String> map){
        System.out.println("Map of items starting with " + prefix);
        for(final Entry<String, String> entry : map.entrySet()){
            System.out.println("\t" + entry.getKey() + ":" + entry.getValue());
        }
        System.out.println("");
    }

}
Run Code Online (Sandbox Code Playgroud)

输出如预期:

Map of items starting with java.
    java.runtime.name:Java(TM) SE Runtime Environment
    java.vm.version:14.2-b01
    java.vm.vendor:Sun Microsystems Inc.
    java.vendor.url:http://java.sun.com/
    java.vm.name:Java HotSpot(TM) Client VM
    java.vm.specification.name:Java Virtual Machine Specification
    java.runtime.version:1.6.0_16-b01
    java.awt.graphicsenv:sun.awt.Win32GraphicsEnvironment
        [... etc]

Map of items starting with hello.
    hello.goodby:You say goodbye and I say hello
    hello:Is it me you're looking for?
    hello.again:Just called to say: hello.
Run Code Online (Sandbox Code Playgroud)


Boz*_*zho 2

恐怕你不能直接。但是你可以

  • 实施ApplicationContextAware并将其设置ApplicationContext为 bean 中的字段。
  • @PostConstruct在方法调用中context.getBean("${aaa.props}")
  • 手动解析结果并将其设置到所需的字段