Truy cập tập tin thuộc tính lập trình với Spring?


137

Chúng tôi sử dụng mã dưới đây để tiêm Spring bean với các thuộc tính từ tệp thuộc tính.

<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>

Có cách nào chúng ta có thể truy cập các thuộc tính theo chương trình không? Tôi đang cố gắng thực hiện một số mã mà không cần tiêm phụ thuộc. Vì vậy, tôi muốn có một số mã như thế này:

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

Một ví dụ đầy đủ về việc truy cập tệp thuộc tính vào mùa xuân có tại liên kết sau: bharatonjava.wordpress.com/2012/08/24/ Kẻ

Câu trả lời:


171

Làm thế nào về PropertiesLoaderUtils ?

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

5
đây là một câu hỏi, nó khác với tôi như thế nào và có thêm hai phiếu VÀ được đăng thứ hai ...
Zoidberg

3
Đánh bại tôi, tôi đã không được bỏ phiếu :) Tôi sẽ không sử dụng PropertyPlaceholderConfigurer, mặc dù nó quá mức cho nhiệm vụ.
skaffman

5
Tôi đã cố gắng đến gần với những gì anh ta có thể, tôi đã bị hạ bệ rất nhiều lần vì không cung cấp đủ chi tiết. Dù sao đi nữa, câu trả lời của bạn xứng đáng với số phiếu bầu, vì nó là chính xác, tôi đoán tôi chỉ ghen tị vì tôi cũng không nhận được 2 phiếu, LOL.
Zoidberg

1
Chúng ta nên cung cấp gì trong đường dẫn nếu tệp được đặt trong thư mục bên ngoài, giả sử thư mục cấu hình?
prnjn

52

Nếu tất cả những gì bạn muốn làm là truy cập giá trị giữ chỗ từ mã, có @Valuechú thích:

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

Để truy cập giữ chỗ Từ SPEL, hãy sử dụng cú pháp này:

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

Để hiển thị cấu hình cho các chế độ xem đã tắt SPEL, người ta có thể sử dụng mẹo này:

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

Và sau đó sử dụng bộ mở rộng để hiển thị các thuộc tính cho một khung nhìn:

<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>

Sau đó, trong chế độ xem, sử dụng các thuộc tính được hiển thị như thế này:

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

Giải pháp này có lợi thế là bạn có thể dựa vào việc triển khai giữ chỗ tiêu chuẩn được đưa vào bởi ngữ cảnh: thẻ giữ chỗ thuộc tính.

Bây giờ là lưu ý cuối cùng, nếu bạn thực sự cần phải nắm bắt tất cả các thuộc tính giữ chỗ và các giá trị của chúng, bạn phải chuyển chúng qua StringValueResolver để đảm bảo rằng các trình giữ chỗ hoạt động bên trong các giá trị thuộc tính như mong đợi. Các mã sau đây sẽ làm điều đó.

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 cho câu trả lời rất đầy đủ này! Có cách nào để làm điều này với các lĩnh vực cuối cùng?
Phường

2
@WardC bạn không thể đưa vào trường cuối cùng. Tuy nhiên, bạn có thể đưa vào một đối số của hàm tạo và đặt giá trị trường cuối cùng bên trong hàm tạo. Xem stackoverflow.com/questions/2306078/ và và stackoverflow.com/questions/4203302/
Đổi

50

CREDIT : Truy cập theo chương trình vào các thuộc tính trong Spring mà không cần đọc lại tệp thuộc tính

Tôi đã tìm thấy một triển khai tốt đẹp của việc truy cập các thuộc tính theo chương trình vào mùa xuân mà không cần tải lại các thuộc tính tương tự mà mùa xuân đã tải. [Ngoài ra, không bắt buộc phải mã hóa vị trí tệp thuộc tính trong nguồn]

Với những thay đổi này, mã trông sạch hơn và dễ bảo trì hơn.

Khái niệm khá là đơn giản. Chỉ cần mở rộng trình giữ chỗ thuộc tính mặc định mùa xuân (PropertyPlaceholderConfigker) và nắm bắt các thuộc tính mà nó tải trong biến cục bộ

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

}

Ví dụ sử dụng

SpringPropertiesUtil.getProperty("myProperty")

Thay đổi cấu hình mùa xuân

<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>

Hy vọng điều này sẽ giúp giải quyết các vấn đề bạn có


8
Đây không phải là một thực hiện đầy đủ và sẽ không hoạt động chính xác. PropertyPlaceholderConfigker sử dụng PropertyPlaceholderHelper để thay thế TẤT CẢ các thuộc tính giữ chỗ, bao gồm cả các trình giữ chỗ lồng nhau. Trong triển khai của Kalinga nếu bạn có thứ gì đó như myFile = $ {myFolder} /myFile.txt, giá trị thuộc tính theo nghĩa đen bạn sẽ nhận được từ bản đồ bằng khóa "myFile" sẽ là $ {myFolder} /myFile.txt.

1
Đây là giải pháp chính xác. Để giải quyết mối quan tâm của Brian. $ {MyFolder} phải là thuộc tính hệ thống và không có trong tệp thuộc tính. Điều này có thể được giải quyết bằng cách đặt thuộc tính hệ thống tomcat hoặc chạy thuộc tính được đặt trong nhật thực. Bạn thậm chí có thể có một tài sản xây dựng. Giải pháp này giả định rằng một chút và nên giải quyết vấn đề đó nhưng đồng thời câu trả lời này còn hơn cả dòng thực hành tiêu chuẩn để tải các thuộc tính mùa xuân và java ở một nơi thay vì riêng biệt. Một tùy chọn khác là tải một tệp thuộc tính chung với myFile trong tệp và sử dụng tệp đó để lấy phần còn lại.
Cướp

1
Tôi đã cố gắng áp dụng cách giải quyết này cho 'new' PropertySourcePlaceholderConfigker từ Spring 3.1+ nhưng tôi thấy rằng các phương thức processProperives (ConfigurableListableBeanFactory beanFactory, các đạo cụ thuộc tính) hiện không được chấp nhận và do đó không có quyền truy cập vào đối số 'đạo cụ'. Nhìn vào các nguồn của PropertySourcePlaceholderConfigker không thể tìm thấy một cách rõ ràng để lộ các thuộc tính. Bất kỳ ý tưởng để làm điều đó? Cảm ơn!
Jorge Palacio

48

Tôi đã làm điều này và nó đã làm việc.

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

Cần làm việc.


25

Bạn cũng có thể sử dụng các tiện ích lò xo hoặc tải các thuộc tính thông qua PropertiesFactoryBean.

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

hoặc là:

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

Sau đó, bạn có thể chọn chúng trong ứng dụng của mình với:

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

và sử dụng thêm các thuộc tính này trong cấu hình của bạn:

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

Điều này cũng có trong các tài liệu: http://docs.spring.io/spring/docs/civerse/spring-framework-reference/htmlsingle/#xsd-config-body-schemas-util-properies


10

Tạo một lớp như dưới đây

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

        }

    }

Sau đó, bất cứ nơi nào bạn muốn truy cập vào một tài sản sử dụng

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

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

- viết getters và setters trong lớp accessor

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

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

1
Cho đến nay câu trả lời tốt nhất, chỉ nên tự động môi trường.
sbochins

4

Như bạn đã biết, các phiên bản mới hơn của Spring không sử dụng PropertyPlaceholderConfigker và bây giờ sử dụng một cấu trúc ác mộng khác gọi là PropertySourcePlaceholderConfigker. Nếu bạn đang cố gắng để có được các thuộc tính được giải quyết từ mã và mong muốn nhóm Spring đã cho chúng tôi một cách để làm điều này từ lâu, thì hãy bỏ phiếu cho bài đăng này! ... Bởi vì đây là cách bạn làm theo cách mới:

Phân lớp propertySourcePlaceholderConfigker:

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

Để sử dụng nó, hãy đảm bảo sử dụng lớp con của bạn trong @Configuration của bạn và lưu lại một tham chiếu đến nó để sử dụng sau.

@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;
    }
}

Sử dụng:

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

2

Đây là một mẫu khác.

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

2

Điều này giúp tôi:

ApplicationContextUtils.getApplicationContext().getEnvironment()

Gói nào là ApplicationContextUtils in
Luke

2

Điều này sẽ giải quyết bất kỳ thuộc tính lồng nhau.

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

Bạn có thể có được tài sản của bạn thông qua Environmentlớp học. Như tài liệu đứng:

Các thuộc tính đóng vai trò quan trọng trong hầu hết tất cả các ứng dụng và có thể bắt nguồn từ nhiều nguồn khác nhau: tệp thuộc tính, thuộc tính hệ thống JVM, biến môi trường hệ thống, JNDI, tham số ngữ cảnh servlet, đối tượng Thuộc tính ad-hoc, Bản đồ, v.v. Vai trò của đối tượng môi trường liên quan đến các thuộc tính là cung cấp cho người dùng giao diện dịch vụ thuận tiện để định cấu hình các nguồn thuộc tính và giải quyết các thuộc tính từ chúng.

Có môi trường như một envbiến, chỉ cần gọi:

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

Bạn có thể nhận được các thuộc tính 'thô' của mình thông qua:

env.getProperty("your-property")

Nó sẽ tìm kiếm thông qua tất cả các nguồn tài sản mà mùa xuân đã đăng ký.

Bạn có thể có được Môi trường thông qua:

  • tiêm ApplicationContext bằng cách thực hiện ApplicationContextAwarevà sau đó gọigetEnvironment() vào ngữ cảnh
  • thực hiện EnvironmentAware.

Nó có được thông qua việc thực hiện một lớp vì các thuộc tính được giải quyết trong giai đoạn đầu khởi động ứng dụng, vì chúng có thể được yêu cầu để xây dựng bean.

Đọc thêm về tài liệu: tài liệu môi trường mùa xuân


1

Bài đăng này cũng khám phá cách truy cập các thuộc tính: http://maciej-miklas.blogspot.de/2013/07/spring-31-programmatic-access-to.html

Bạn có thể truy cập các thuộc tính được tải bởi trình giữ chỗ thuộc tính mùa xuân trên bean mùa xuân như vậy:

@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" />`

trong servlet-bối cảnh sau đó bạn có thể trực tiếp sử dụng tệp của mình ở mọi nơi


0

Vui lòng sử dụng mã dưới đây trong tệp cấu hình mùa xuân của bạn để tải tệp từ đường dẫn lớp của ứng dụng của bạn

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

0

Đây là cách tốt nhất để tôi làm việc:

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);
    }
}

Khởi tạo lớp và phương thức gọi obj.getProperty ("my.property.name");
Daniel Almeida
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.