如何使用 Spring 框架从属性文件中获取值到 Map 中?

Posted

技术标签:

【中文标题】如何使用 Spring 框架从属性文件中获取值到 Map 中?【英文标题】:How to get values from property-file into Map using Spring framework? 【发布时间】:2011-04-06 05:34:44 【问题描述】:

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

@Value("$aaa.prop")
public String someProp;

但我想要更多……

例如我有一些属性文件:

aaa.props=p1,p2,p3
aaa.props.p1=qwe
aaa.props.p2=asd
aaa.props.p3=zxc

我确定它包含属性aaa.props,而对其他属性一无所知。我想使用这样的代码来映​​射这些属性:

@Value ("$aaa.props") 
public Map<String, String> someProps;

生成的一些道具:p1=qwe,p2=asd,p3=zxc

【问题讨论】:

您可能会发现这个问题的答案很有用:***.com/questions/9259819/…。注入属性对象作为资源,解析列表一并相应地构建您的地图。 【参考方案1】:

好吧,我为您构建了一个通用方法:一个工厂 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;
    


这是一个带有一些示例用法的 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>

这是一个测试类:

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("");
    


输出如预期:

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.

【讨论】:

AbstractFactoryBean 默认为单例。在一个上下文中多次使用这个bean(具有不同的属性)会不会有问题? @naXa 这个答案是 4 岁。这些天 FactoryBeans 有点被弃用了。我会改用 \@Configuration 类【参考方案2】:

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

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

【讨论】:

有没有办法让所有属性找到我需要的?【参考方案3】:

你可以使用@Value

属性文件:

aaa.props=p1:'qwe',p2:'asd',p3:'zxc'

Java 代码:

@Value("#$aaa.props")
private Map<String,String> someProps;

【讨论】:

这是应该被赞成和接受的答案。此外,那些使用基于 Spring XML 的配置的人可以简单地使用诸如 p:someProps="#$aaa.props" 之类的属性来注入它。【参考方案4】:

你可以这样做: Maven依赖

<dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.2</version>
    </dependency>

添加导入。

import javax.annotation.Resource;

...

@Resource (name="propertiesMapName") 
public Properties someProps;

在您的 spring xml 应用程序上下文中:

<util:properties id="propertiesMapName" location="classpath:yourFile.properties"/>

你将需要这个命名空间

xmlns:util="http://www.springframework.org/schema/util"

http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.1.xsd

【讨论】:

我能知道为什么我的解决方案中有-1吗?这很有效,我认为这是一种非常干净的方式,我想了解什么是错的。谢谢【参考方案5】:

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config上定义的解决方案

@ConfigurationProperties(prefix="my")
public class Config 

    private List<String> servers = new ArrayList<String>();

    public List<String> getServers() 
        return this.servers;
    

【讨论】:

以上是关于如何使用 Spring 框架从属性文件中获取值到 Map 中?的主要内容,如果未能解决你的问题,请参考以下文章

如何注入值到Spring bean属性

注入值到Spring bean属性

如何从 CoreData-Entities 获取一些值到代码中

从spring boot模型视图对象获取值到角度JS 5

从html获取数据属性值到jquery

如何在 Spring 中使用从属性文件获取的错误消息的注释验证?