Spring을 사용하여 프로그래밍 방식으로 속성 파일에 액세스 하시겠습니까?


137

아래 코드를 사용하여 속성 파일의 속성으로 Spring Bean을 주입합니다.

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:/my.properties"/>
</bean>

<bean id="blah" class="abc">
    <property name="path" value="${the.path}"/>
</bean>

프로그래밍 방식으로 속성에 액세스 할 수있는 방법이 있습니까? 의존성 주입없이 코드를 작성하려고합니다. 따라서 다음과 같은 코드를 갖고 싶습니다.

PropertyPlaceholderConfigurer props = new PropertyPlaceholderConfigurer();
props.load("classpath:/my.properties");
props.get("path");

봄에 속성 파일에 액세스하는 완전한 예는 다음 링크에 있습니다. bharatonjava.wordpress.com/2012/08/24/…

답변:


171

어떻게 PropertiesLoaderUtils ?

Resource resource = new ClassPathResource("/my.properties");
Properties props = PropertiesLoaderUtils.loadProperties(resource);

5
여기에 질문이 있습니다. 이건 내 것과 어떻게 다른지, 그리고 두 개의 투표가 더 있고 두 번째로 게시되었습니다 ...
Zoidberg

3
나를 이길, 나는 투표를하지 않았다 :) 나는 PropertyPlaceholderConfigurer작업을 위해 과잉이지만을 사용하지 않을 것 입니다.
skaffman 2016

5
나는 그가 가졌던 것에 최대한 가까워 지려고 노력했다. 나는 충분한 세부 사항을 제공하지 않아서 여러 번 하향 투표를 받았다. 어쨌든, 당신의 대답은 정확하기 때문에 투표를받을 가치가 있습니다. 나는 단지 2 표를 얻지 못했습니다 .LOL.
Zoidberg

1
파일이 외부 디렉토리에 있으면 경로에 무엇을 주어야합니까? config 폴더라고 가정 해 봅시다.
prnjn

52

코드에서 자리 표시 자 값에 액세스하기 만하면 @Value주석이 있습니다.

@Value("${settings.some.property}")
String someValue;

자리 표시 자에 액세스하려면 SPEL에서 다음 구문을 사용하십시오.

#('${settings.some.property}')

SPEL이 꺼진보기에 구성을 노출하려면 다음 트릭을 사용할 수 있습니다.

package com.my.app;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class PropertyPlaceholderExposer implements Map<String, String>, BeanFactoryAware {  
    ConfigurableBeanFactory beanFactory; 

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = (ConfigurableBeanFactory) beanFactory;
    }

    protected String resolveProperty(String name) {
        String rv = beanFactory.resolveEmbeddedValue("${" + name + "}");

        return rv;
    }

    @Override
    public String get(Object key) {
        return resolveProperty(key.toString());
    }

    @Override
    public boolean containsKey(Object key) {
        try {
            resolveProperty(key.toString());
            return true;
        }
        catch(Exception e) {
            return false;
        }
    }

    @Override public boolean isEmpty() { return false; }
    @Override public Set<String> keySet() { throw new UnsupportedOperationException(); }
    @Override public Set<java.util.Map.Entry<String, String>> entrySet() { throw new UnsupportedOperationException(); }
    @Override public Collection<String> values() { throw new UnsupportedOperationException(); }
    @Override public int size() { throw new UnsupportedOperationException(); }
    @Override public boolean containsValue(Object value) { throw new UnsupportedOperationException(); }
    @Override public void clear() { throw new UnsupportedOperationException(); }
    @Override public String put(String key, String value) { throw new UnsupportedOperationException(); }
    @Override public String remove(Object key) { throw new UnsupportedOperationException(); }
    @Override public void putAll(Map<? extends String, ? extends String> t) { throw new UnsupportedOperationException(); }
}

그런 다음 노출기를 사용하여 속성을 뷰에 노출하십시오.

<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="tilesViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
    <property name="attributesMap">
        <map>
            <entry key="config">
                <bean class="com.my.app.PropertyPlaceholderExposer" />
            </entry>
        </map>
    </property>
</bean>

그런 다음, 다음과 같이 노출 된 속성을 사용하십시오.

${config['settings.some.property']}

이 솔루션은 context : property-placeholder 태그로 삽입 된 표준 자리 표시 자 구현에 의존 할 수 있다는 이점이 있습니다.

마지막으로, 모든 자리 표시 자 속성 및 해당 값을 캡처해야하는 경우 StringValueResolver를 통해 해당 값을 파이프하여 자리 표시자가 예상대로 속성 값 내에서 작동하도록해야합니다. 다음 코드가이를 수행합니다.

package com.my.app;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.util.StringValueResolver;

public class AppConfig extends PropertyPlaceholderConfigurer implements Map<String, String> {

    Map<String, String> props = new HashMap<String, String>();

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
            throws BeansException {

        this.props.clear();
        for (Entry<Object, Object> e: props.entrySet())
            this.props.put(e.getKey().toString(), e.getValue().toString());

        super.processProperties(beanFactory, props);
    }

    @Override
    protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
            StringValueResolver valueResolver) {

        super.doProcessProperties(beanFactoryToProcess, valueResolver);

        for(Entry<String, String> e: props.entrySet())
            e.setValue(valueResolver.resolveStringValue(e.getValue()));
    }

    // Implement map interface to access stored properties
    @Override public Set<String> keySet() { return props.keySet(); }
    @Override public Set<java.util.Map.Entry<String, String>> entrySet() { return props.entrySet(); }
    @Override public Collection<String> values() { return props.values(); }
    @Override public int size() { return props.size(); }
    @Override public boolean isEmpty() { return props.isEmpty(); }
    @Override public boolean containsValue(Object value) { return props.containsValue(value); }
    @Override public boolean containsKey(Object key) { return props.containsKey(key); }
    @Override public String get(Object key) { return props.get(key); }
    @Override public void clear() { throw new UnsupportedOperationException(); }
    @Override public String put(String key, String value) { throw new UnsupportedOperationException(); }
    @Override public String remove(Object key) { throw new UnsupportedOperationException(); }
    @Override public void putAll(Map<? extends String, ? extends String> t) { throw new UnsupportedOperationException(); }
}

이 완벽한 답변을위한 Thnx! 최종 필드로 이것을 수행하는 방법이 있습니까?
Ward

2
@WardC 최종 필드에 주입 할 수 없습니다. 그러나 생성자 인수를 삽입하고 생성자 내에서 최종 필드 값을 설정할 수 있습니다. 참조 stackoverflow.com/questions/2306078/...stackoverflow.com/questions/4203302/...
앤트 틱스

50

신용 : 속성 파일을 다시 읽지 않고 Spring의 속성에 프로그래밍 방식으로 액세스

스프링이 이미로드 한 것과 동일한 속성을 다시로드하지 않고 스프링에서 프로그래밍 방식으로 속성에 액세스하는 훌륭한 구현을 발견했습니다. [또한 소스에서 속성 파일 위치를 하드 코딩 할 필요는 없습니다]

이러한 변경으로 코드가 더 깨끗하고 유지 관리가 용이 ​​해 보입니다.

개념은 매우 간단합니다. 스프링 기본 속성 자리 표시 자 (PropertyPlaceholderConfigurer)를 확장하고 로컬 변수에로드 된 속성을 캡처하십시오.

public class SpringPropertiesUtil extends PropertyPlaceholderConfigurer {

    private static Map<String, String> propertiesMap;
    // Default as in PropertyPlaceholderConfigurer
    private int springSystemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK;

    @Override
    public void setSystemPropertiesMode(int systemPropertiesMode) {
        super.setSystemPropertiesMode(systemPropertiesMode);
        springSystemPropertiesMode = systemPropertiesMode;
    }

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) throws BeansException {
        super.processProperties(beanFactory, props);

        propertiesMap = new HashMap<String, String>();
        for (Object key : props.keySet()) {
            String keyStr = key.toString();
            String valueStr = resolvePlaceholder(keyStr, props, springSystemPropertiesMode);
            propertiesMap.put(keyStr, valueStr);
        }
    }

    public static String getProperty(String name) {
        return propertiesMap.get(name).toString();
    }

}

사용 예

SpringPropertiesUtil.getProperty("myProperty")

스프링 구성 변경

<bean id="placeholderConfigMM" class="SpringPropertiesUtil">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
    <property name="locations">
    <list>
        <value>classpath:myproperties.properties</value>
    </list>
    </property>
</bean>

이것이 당신이 가진 문제를 해결하는 데 도움이되기를 바랍니다.


8
이것은 전체 구현이 아니며 올바르게 작동하지 않습니다. PropertyPlaceholderConfigurer는 PropertyPlaceholderHelper를 사용하여 중첩 된 플레이스 홀더를 포함한 모든 플레이스 홀더 특성을 대체합니다. Kalinga의 구현에서 myFile = $ {myFolder} /myFile.txt와 같은 것이 있으면 "myFile"키를 사용하여 맵에서 얻을 수있는 리터럴 속성 값은 $ {myFolder} /myFile.txt입니다.

1
이것이 올바른 해결책입니다. 브라이언의 우려를 해결하기 위해. $ {myFolder}는 시스템 특성이어야하며 특성 파일에 없어야합니다. 이것은 바람둥이 시스템 속성 또는 실행 속성을 일식으로 설정하여 해결할 수 있습니다. 빌드 속성을 가질 수도 있습니다. 이 솔루션은 약간을 가정하고 해결해야하지만 동시에이 답변은 스프링과 Java 속성을 별도로 대신하는 대신 한곳에서 표준 연습을 수행하는 데 훨씬 더 많습니다. 또 다른 옵션은 파일에 myFile과 함께 일반 특성 파일을로드하고 나머지를 가져 오는 데 사용하는 것입니다.
Rob

1
이 해결 방법을 Spring 3.1+의 '새로운'PropertySourcesPlaceholderConfigurer에 적용하려고 시도했지만 processProperties (ConfigurableListableBeanFactory beanFactory, Properties props) 메소드가 더 이상 사용되지 않으므로 'props'인수에 액세스 할 수 없습니다. PropertySourcesPlaceholderConfigurer의 소스를 살펴보면 속성을 노출하는 명확한 방법을 찾을 수 없습니다. 그것을 할 아이디어가 있습니까? 감사!
Jorge Palacio

48

나는 이것을했고 그것이 효과가 있었다.

Properties props = PropertiesLoaderUtils.loadAllProperties("my.properties");
PropertyPlaceholderConfigurer props2 = new PropertyPlaceholderConfigurer();
props2.setProperties(props);

작동합니다.


25

스프링 유틸리티를 사용하거나 PropertiesFactoryBean을 통해 속성을로드 할 수도 있습니다.

<util:properties id="myProps" location="classpath:com/foo/myprops.properties"/>

또는:

<bean id="myProps" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <property name="location" value="classpath:com/foo/myprops.properties"/>
</bean>

그런 다음 응용 프로그램에서 다음을 사용하여 선택할 수 있습니다.

@Resource(name = "myProps")
private Properties myProps;

구성에서 다음 속성을 추가로 사용하십시오.

<context:property-placeholder properties-ref="myProps"/>

이것은 또한 문서에 있습니다 : http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#xsd-config-body-schemas-util-properties


10

아래와 같은 클래스를 만듭니다

    package com.tmghealth.common.util;

    import java.util.Properties;

    import org.springframework.beans.BeansException;

    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

    import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

    import org.springframework.context.annotation.Configuration;

    import org.springframework.context.annotation.PropertySource;

    import org.springframework.stereotype.Component;


    @Component
    @Configuration
    @PropertySource(value = { "classpath:/spring/server-urls.properties" })
    public class PropertiesReader extends PropertyPlaceholderConfigurer {

        @Override
        protected void processProperties(
                ConfigurableListableBeanFactory beanFactory, Properties props)
                throws BeansException {
            super.processProperties(beanFactory, props);

        }

    }

그런 다음 속성 사용에 액세스하려는 곳

    @Autowired
        private Environment environment;
    and getters and setters then access using 

    environment.getProperty(envName
                    + ".letter.fdi.letterdetails.restServiceUrl");

-접근 자 클래스에서 getter 및 setter 작성

    public Environment getEnvironment() {
            return environment;
        }`enter code here`

        public void setEnvironment(Environment environment) {
            this.environment = environment;
        }

1
지금까지 가장 좋은 대답은 환경을 자동으로 연결하는 것입니다.
sbochins

4

최신 버전의 Spring은 PropertyPlaceholderConfigurer를 사용하지 않으며 이제 PropertySourcesPlaceholderConfigurer라는 또 다른 악몽 같은 구성을 사용합니다. 코드에서 해결 된 속성을 얻으려고 노력하고 스프링 팀이 오래 전에이 작업을 수행 할 수있는 방법을 원한다면이 게시물에 투표하십시오! ... 이것이 새로운 방식으로 수행되기 때문에 :

서브 클래스 PropertySourcesPlaceholderConfigurer :

public class SpringPropertyExposer extends PropertySourcesPlaceholderConfigurer {

    private ConfigurableListableBeanFactory factory;

    /**
     * Save off the bean factory so we can use it later to resolve properties
     */
    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
            final ConfigurablePropertyResolver propertyResolver) throws BeansException {
        super.processProperties(beanFactoryToProcess, propertyResolver);

        if (beanFactoryToProcess.hasEmbeddedValueResolver()) {
            logger.debug("Value resolver exists.");
            factory = beanFactoryToProcess;
        }
        else {
            logger.error("No existing embedded value resolver.");
        }
    }

    public String getProperty(String name) {
        Object propertyValue = factory.resolveEmbeddedValue(this.placeholderPrefix + name + this.placeholderSuffix);
        return propertyValue.toString();
    }
}

이를 사용하려면 @Configuration에서 서브 클래스를 사용하고 나중에 사용할 수 있도록 참조를 저장하십시오.

@Configuration
@ComponentScan
public class PropertiesConfig {

    public static SpringPropertyExposer commonEnvConfig;

    @Bean(name="commonConfig")
    public static PropertySourcesPlaceholderConfigurer commonConfig() throws IOException {
        commonEnvConfig = new SpringPropertyExposer(); //This is a subclass of the return type.
        PropertiesFactoryBean commonConfig = new PropertiesFactoryBean();
        commonConfig.setLocation(new ClassPathResource("META-INF/spring/config.properties"));
        try {
            commonConfig.afterPropertiesSet();
        }
        catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
        commonEnvConfig.setProperties(commonConfig.getObject());
        return commonEnvConfig;
    }
}

용법:

Object value = PropertiesConfig.commonEnvConfig.getProperty("key.subkey");

2

여기 또 다른 샘플이 있습니다.

XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
cfg.postProcessBeanFactory(factory);

2

이것은 나를 도와줍니다 :

ApplicationContextUtils.getApplicationContext().getEnvironment()

ApplicationContextUtils에 포함 된 패키지
Luke

2

중첩 된 속성이 해결됩니다.

public class Environment extends PropertyPlaceholderConfigurer {

/**
 * Map that hold all the properties.
 */
private Map<String, String> propertiesMap; 

/**
 * Iterate through all the Property keys and build a Map, resolve all the nested values before building the map.
 */
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) throws BeansException {
    super.processProperties(beanFactory, props);

    propertiesMap = new HashMap<String, String>();
    for (Object key : props.keySet()) {
        String keyStr = key.toString();
        String valueStr = beanFactory.resolveEmbeddedValue(placeholderPrefix + keyStr.trim() + DEFAULT_PLACEHOLDER_SUFFIX);
        propertiesMap.put(keyStr, valueStr);
    }
} 

/**
 * This method gets the String value for a given String key for the property files.
 * 
 * @param name - Key for which the value needs to be retrieved.
 * @return Value
 */
public String getProperty(String name) {
    return propertiesMap.get(name).toString();
}

2

Environment수업을 통해 속성을 얻을 수 있습니다 . 문서가 의미하는대로 :

특성은 거의 모든 응용 프로그램에서 중요한 역할을하며 특성 파일, JVM 시스템 특성, 시스템 환경 변수, JNDI, 서블릿 컨텍스트 매개 변수, 임시 특성 오브젝트, 맵 등 다양한 소스에서 유래 할 수 있습니다. 속성과 관련된 환경 개체의 역할은 사용자에게 속성 소스를 구성하고 속성을 확인하기위한 편리한 서비스 인터페이스를 제공하는 것입니다.

환경을 env변수로 사용하려면 다음을 호출하십시오.

env.resolvePlaceholders("${your-property:default-value}")

다음을 통해 '원시'속성을 얻을 수 있습니다.

env.getProperty("your-property")

스프링이 등록한 모든 속성 소스를 검색합니다.

다음을 통해 환경을 얻을 수 있습니다.

  • 구현 ApplicationContextAware하고 ApplicationContext 를 호출 getEnvironment()하여 ApplicationContext를 주입 하십시오 .
  • 구현하십시오 EnvironmentAware.

특성은 Bean 구성에 필요할 수 있으므로 애플리케이션 시작 초기 단계에서 분석되므로 클래스 구현을 통해 얻을 수 있습니다.

설명서에 대한 자세한 내용 : 스프링 환경 설명서


1

이 게시물은 속성에 액세스하는 방법도 explatis입니다. .

이러한 스프링 빈을 통해 스프링 속성 자리 표시자가로드 한 속성에 액세스 할 수 있습니다.

@Named
public class PropertiesAccessor {

    private final AbstractBeanFactory beanFactory;

    private final Map<String,String> cache = new ConcurrentHashMap<>();

    @Inject
    protected PropertiesAccessor(AbstractBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public  String getProperty(String key) {
        if(cache.containsKey(key)){
            return cache.get(key);
        }

        String foundProp = null;
        try {
            foundProp = beanFactory.resolveEmbeddedValue("${" + key.trim() + "}");
            cache.put(key,foundProp);
        } catch (IllegalArgumentException ex) {
           // ok - property was not found
        }

        return foundProp;
    }
}

0
create .properties file in classpath of your project and add path configuration in xml`<context:property-placeholder location="classpath*:/*.properties" />`

그 후 servlet-context.xml에서 u는 어디서나 파일을 직접 사용할 수 있습니다


0

스프링 구성 파일에서 아래 코드를 사용하여 응용 프로그램의 클래스 경로에서 파일을로드하십시오.

 <context:property-placeholder
    ignore-unresolvable="true" ignore-resource-not-found="false" location="classpath:property-file-name" />

0

이것이 내가 작동하게하는 가장 좋은 방법입니다.

package your.package;

import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

public class ApplicationProperties {

    private Properties properties;

    public ApplicationProperties() {
        // application.properties located at src/main/resource
        Resource resource = new ClassPathResource("/application.properties");
        try {
            this.properties = PropertiesLoaderUtils.loadProperties(resource);
        } catch (IOException ex) {
            Logger.getLogger(ApplicationProperties.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public String getProperty(String propertyName) {
        return this.properties.getProperty(propertyName);
    }
}

클래스를 인스턴스화하고 메소드를 호출하십시오. obj.getProperty ( "my.property.name");
다니엘 알메이다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.