Доступ к файлу свойств программно с помощью Spring?
Мы используем код ниже, чтобы внедрить бины Spring со свойствами из файла свойств.
<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");
17 ответов
Как насчет PropertiesLoaderUtils?
Resource resource = new ClassPathResource("/my.properties");
Properties props = PropertiesLoaderUtils.loadProperties(resource);
Если все, что вы хотите сделать, это получить доступ к значению заполнителя из кода, есть @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(); }
}
А затем используйте exposer для предоставления свойств представлению:
<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(); }
}
Я сделал это, и это сработало.
Properties props = PropertiesLoaderUtils.loadAllProperties("my.properties");
PropertyPlaceholderConfigurer props2 = new PropertyPlaceholderConfigurer();
props2.setProperties(props);
Это должно работать.
КРЕДИТ: Программный доступ к свойствам в 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")
Изменения конфигурации Spring
<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>
Надеюсь, это поможет решить ваши проблемы
Вы также можете использовать утилиты Spring или загрузить свойства через 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/
Создайте класс, как показано ниже
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");
- написать геттеры и сеттеры в классе доступа
public Environment getEnvironment() {
return environment;
}`enter code here`
public void setEnvironment(Environment environment) {
this.environment = environment;
}
Вы можете получить свои свойства через Environment
учебный класс. В качестве документации выступает:
Свойства играют важную роль практически во всех приложениях и могут быть получены из различных источников: файлов свойств, системных свойств JVM, системных переменных среды, JNDI, параметров контекста сервлета, специальных объектов свойств, карт и т. Д. Роль объекта среды по отношению к свойствам заключается в предоставлении пользователю удобного служебного интерфейса для настройки источников свойств и разрешения свойств из них.
Иметь окружающую среду как env
переменная, просто вызовите:
env.resolvePlaceholders("${your-property:default-value}")
Вы можете получить свои "сырые" свойства через:
env.getProperty("your-property")
Он будет искать по всем источникам свойств, которые были зарегистрированы весной.
Вы можете получить Среду через:
- внедрить ApplicationContext путем реализации
ApplicationContextAware
а затем позвонитеgetEnvironment()
в контексте - воплощать в жизнь
EnvironmentAware
,
Это достигается за счет реализации класса, потому что свойства разрешаются на ранней стадии запуска приложения, так как они могут потребоваться для построения компонента.
Подробнее о документации: весенняя экологическая документация
Как вы знаете, более новые версии Spring не используют PropertyPlaceholderConfigurer, а теперь используют другую кошмарную конструкцию с именем PropertySourcesPlaceholderConfigurer. Если вы пытаетесь получить разрешенные свойства из кода и хотите, чтобы команда Spring дала нам способ сделать это давным-давно, тогда проголосуйте за этот пост! ... Потому что так ты это делаешь по-новому:
Подкласс 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");
Это поможет мне:
ApplicationContextUtils.getApplicationContext().getEnvironment()
Вот еще один пример.
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
cfg.postProcessBeanFactory(factory);
Это разрешит любые вложенные свойства.
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();
}
Просто ввести Environment
и вызовите getProperty для этого.
@Autowired
private Environment env;
void foo() {
env.getProperty("your.property");
}
Этот пост также объясняет, как получить доступ к свойствам: http://maciej-miklas.blogspot.de/2013/07/spring-31-programmatic-access-to.html
Вы можете получить доступ к свойствам, загружаемым Spring-свойством-заполнителем поверх такого bean-компонента:
@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;
}
}
Это самый лучший способ, которым я заставил это работать:
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);
}
}
create .properties file in classpath of your project and add path configuration in xml`<context:property-placeholder location="classpath*:/*.properties" />`
в servlet-context.xml после этого вы можете напрямую использовать ваш файл везде
Я знаю, что это старая ветка, однако, на мой взгляд, эта тема становится очень важной для тех, кто использует функциональный подход для всех тех случаев использования, где вам нужен микросервис, который загружается «мгновенно», и поэтому вы избегаете использования аннотаций. Проблема, которая осталась нерешенной, заключалась в том, чтобы в конечном итоге загрузить переменные среды, которые у меня были в моем application.yml.
public class AppPropsLoader {
public static Properties load() {
var propPholderConfig = new PropertySourcesPlaceHolderConfigurer();
var yaml = new YamlPropertiesFactoryBean();
ClassPathResource resource = new ClassPathResource("application.yml");
Objects.requireNonNull(resource, "File application.yml does not exist");
yaml.setResources(resource);
Objects.requireNonNull(yaml.getObject(), "Configuration cannot be null");
propPholderConfig.postProcessBeanFactory(new DefaultListableBeanFactory());
propPholderConfig.setProperties(yaml.getObject());
PropertySources appliedPropertySources =
propPholderConfig.getAppliedPropertySources();
var resolver = new PropertySourcesPlaceholderResolver(appliedPropertySources);
Properties resolvedProps = new Properties();
for (Map.Entry<Object, Object> prop: yaml.getObject().entrySet()) {
resolvedProps.setProperty((String)prop.getKey(),
getPropertyValue(resolver.resolvePlaceHolders(prop.getValue()));
}
return resolvedProps;
}
static String getPropertyValue(Object prop) {
var val = String.valueOf(prop);
Pattern p = Pattern.compile("^(\\$\\{)([a-zA-Z0-9-._]+)(\\})$");
Matcher m = p.matcher(val);
if(m.matches()) {
return System.getEnv(m.group(2));
}
return val;
}
}
Пожалуйста, используйте приведенный ниже код в вашем весеннем конфигурационном файле, чтобы загрузить файл из пути к классам вашего приложения
<context:property-placeholder
ignore-unresolvable="true" ignore-resource-not-found="false" location="classpath:property-file-name" />