Spring: доступ ко всем свойствам среды как к объекту «Карта» или «Свойства»

Я использую annotations для настройки моей весенней среды следующим образом:

@Configuration ... @PropertySource("classpath:/config/default.properties") ... public class GeneralApplicationConfiguration implements WebApplicationInitializer { @Autowired Environment env; } 

Это приводит к тому, что мои свойства из default.properties являются частью среды. Я хочу использовать механизм @PropertySource здесь, потому что он уже предоставляет возможность перегрузить свойства через несколько резервных слоев и разных динамических местоположений на основе настроек среды (например, location config_dir). Я просто снял резерв, чтобы упростить пример.

Однако теперь моя проблема заключается в том, что я хочу настроить, например, мои свойства datasource в default.properties. Вы можете передать настройки в источник данных, не зная подробно, какие параметры ожидает источник данных

 Properties p = ... datasource.setProperties(p); 

Однако проблема заключается в том, что объект Environment не является ни объектом Properties, ни Map, ни чем-либо сопоставимым. С моей точки зрения, просто невозможно получить доступ ко всем значениям среды, потому что не существует метода keySet или iteratorа или чего-либо подобного.

 Properties p <=== Environment env? 

Я что-то упускаю? Возможно ли каким-либо образом получить доступ ко всем элементам объекта Environment? Если да, я мог бы сопоставить записи с объектом Map или Properties, я мог бы даже фильтровать или сопоставлять их с помощью префикса – создавать подмножества в качестве стандартной java-карты … Это то, что я хотел бы сделать. Какие-либо предложения?

Вам нужно что-то вроде этого, возможно, это может быть улучшено, это первая попытка:

 ... import org.springframework.core.env.PropertySource; import org.springframework.core.env.AbstractEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; ... @Configuration ... @org.springframework.context.annotation.PropertySource("classpath:/config/default.properties") ... public class GeneralApplicationConfiguration implements WebApplicationInitializer { @Autowired Environment env; public void someMethod() { ... Map map = new HashMap(); for(Iterator it = ((AbstractEnvironment) env).getPropertySources().iterator(); it.hasNext(); ) { PropertySource propertySource = (PropertySource) it.next(); if (propertySource instanceof MapPropertySource) { map.putAll(((MapPropertySource) propertySource).getSource()); } } ... } ... к ... import org.springframework.core.env.PropertySource; import org.springframework.core.env.AbstractEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; ... @Configuration ... @org.springframework.context.annotation.PropertySource("classpath:/config/default.properties") ... public class GeneralApplicationConfiguration implements WebApplicationInitializer { @Autowired Environment env; public void someMethod() { ... Map map = new HashMap(); for(Iterator it = ((AbstractEnvironment) env).getPropertySources().iterator(); it.hasNext(); ) { PropertySource propertySource = (PropertySource) it.next(); if (propertySource instanceof MapPropertySource) { map.putAll(((MapPropertySource) propertySource).getSource()); } } ... } ... 

В принципе, все, что из среды, которая является MapPropertySource (и есть довольно много реализаций), можно получить в виде Map свойств.

Это старый вопрос, но принятый ответ имеет серьезный недостаток. Если объект Spring Environment содержит любые переопределяющие значения (как описано в разделе « Внешняя конфигурация» ), нет никакой гарантии, что отображаемая им карта значений свойств будет соответствовать тем, которые возвращаются из объекта Environment . Я обнаружил, что простое повторение через PropertySource s Environment фактически не дает каких-либо переопределяющих значений. Вместо этого он произвел первоначальное значение, которое должно было быть переопределено.

Вот лучшее решение. Это использует EnumerablePropertySource s Environment для повторения имен известных свойств, но затем считывает фактическое значение из реальной среды Spring. Это гарантирует, что это значение фактически разрешено весной, включая любые переопределяющие значения.

 Properties props = new Properties(); MutablePropertySources propSrcs = ((AbstractEnvironment) springEnv).getPropertySources(); StreamSupport.stream(propSrcs.spliterator(), false) .filter(ps -> ps instanceof EnumerablePropertySource) .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames()) .flatMap(Arrays::stream) .forEach(propName -> props.setProperty(propName, springEnv.getProperty(propName))); 

У меня было требование получить все свойства, ключ которых начинается с отдельного префикса (например, все свойства, начинающиеся с «log4j.appender.») И написал следующий код (используя streamи и lamdas Java 8).

 public static Map getPropertiesStartingWith( ConfigurableEnvironment aEnv, String aKeyPrefix ) { Map result = new HashMap<>(); Map map = getAllProperties( aEnv ); for (Entry entry : map.entrySet()) { String key = entry.getKey(); if ( key.startsWith( aKeyPrefix ) ) { result.put( key, entry.getValue() ); } } return result; } public static Map getAllProperties( ConfigurableEnvironment aEnv ) { Map result = new HashMap<>(); aEnv.getPropertySources().forEach( ps -> addAll( result, getAllProperties( ps ) ) ); return result; } public static Map getAllProperties( PropertySource aPropSource ) { Map result = new HashMap<>(); if ( aPropSource instanceof CompositePropertySource) { CompositePropertySource cps = (CompositePropertySource) aPropSource; cps.getPropertySources().forEach( ps -> addAll( result, getAllProperties( ps ) ) ); return result; } if ( aPropSource instanceof EnumerablePropertySource ) { EnumerablePropertySource ps = (EnumerablePropertySource) aPropSource; Arrays.asList( ps.getPropertyNames() ).forEach( key -> result.put( key, ps.getProperty( key ) ) ); return result; } // note: Most descendants of PropertySource are EnumerablePropertySource. There are some // few others like JndiPropertySource or StubPropertySource myLog.debug( "Given PropertySource is instanceof " + aPropSource.getClass().getName() + " and cannot be iterated" ); return result; } private static void addAll( Map aBase, Map aToBeAdded ) { for (Entry entry : aToBeAdded.entrySet()) { if ( aBase.containsKey( entry.getKey() ) ) { continue; } aBase.put( entry.getKey(), entry.getValue() ); } } 

Обратите внимание, что отправной точкой является ConfigurableEnvironment, которая может возвращать встроенные PropertySources (ConfigurableEnvironment является прямым потомком среды). Вы можете автоупроверить его:

 @Autowired private ConfigurableEnvironment myEnv; 

Если вы не используете очень специальные типы источников ресурсов (например, JndiPropertySource, который обычно не используется при автоконфигурации весны), вы можете получить все свойства, хранящиеся в среде.

Реализация опирается на порядок итераций, который сама по себе обеспечивает и принимает первое найденное свойство, все последующие найденные свойства с тем же именем отбрасываются. Это должно обеспечивать такое же поведение, как если бы окружение запрашивалось непосредственно для свойства (возвращающее первое найденное).

Также обратите внимание, что возвращаемые свойства еще не разрешены, если они содержат псевдонимы с оператором $ {…}. Если вы хотите, чтобы какой-то конкретный ключ был разрешен, вы должны снова спросить Окружающую среду:

 myEnv.getProperty( key ); 

В качестве билета этой весны в Jira это преднамеренный дизайн. Но для меня работает следующий код.

 public static Map getAllKnownProperties(Environment env) { Map rtn = new HashMap<>(); if (env instanceof ConfigurableEnvironment) { for (PropertySource propertySource : ((ConfigurableEnvironment) env).getPropertySources()) { if (propertySource instanceof EnumerablePropertySource) { for (String key : ((EnumerablePropertySource) propertySource).getPropertyNames()) { rtn.put(key, propertySource.getProperty(key)); } } } } return rtn; } 

Попробуйте следующий код:

 ... @Autowired private Environment env; ... for(Iterator> it = ((AbstractEnvironment) env).getPropertySources().iterator(); it.hasNext(); ) { PropertySource propertySource = (PropertySource) it.next(); if (propertySource instanceof CompositePropertySource) { for(Iterator> it2 = ((CompositePropertySource) propertySource).getPropertySources().iterator(); it2.hasNext(); ) { PropertySource propertySource2 = (PropertySource) it2.next(); if (propertySource2 instanceof ResourcePropertySource) { for (Entry entry : ((ResourcePropertySource)propertySource2).getSource().entrySet()) { if (entry.getValue() instanceof String) { System.out.println(entry.getKey() + "=" + (String)entry.getValue()); } } } } } } 

В других ответах было указано решение большинства случаев, связанных с PropertySources , но никто не упомянул, что некоторые источники свойств не могут быть переведены в полезные типы.

Одним из таких примеров является источник свойств аргументов командной строки. Класс, который используется, – SimpleCommandLinePropertySource . Этот частный class возвращается общедоступным методом, что делает его чрезвычайно сложным для доступа к данным внутри объекта. Я должен был использовать рефлексию, чтобы читать данные и в конечном итоге заменить источник собственности.

Если у кого-то есть лучшее решение, я бы очень хотел это увидеть; однако, это единственный взлом, который я получил на работу.

  • Лучший способ обработки наследования объектов в Spring Data JPA
  • Как создать пользовательские методы для использования в выражениях выражения выражения весны безопасности
  • динамически объявлять бобы во время выполнения весной
  • Привязка списка в @RequestParam
  • Получить прокси-сервер AOP от самого объекта
  • Как проверить поддержку декларативного кэширования Spring в хранилищах Spring Data?
  • @Transactional метод вызова другого метода без @Transactional anotation?
  • Как получить пользовательскую информацию пользователя от сервера авторизации сервера / пользователя OAuth2
  • Война с весенними ботинками без встроенного tomcat
  • Общие сведения о сохранении и обновлении Spring Cloud Eureka Server
  • Как использовать OAuth2RestTemplate?
  • Interesting Posts

    Метод count count vs Count ()?

    Почему некорректная попытка пароля занимает намного больше времени, чем правильная?

    Как добавить параметры в HttpURLConnection с помощью POST с помощью NameValuePair

    Могу ли я иметь несколько сервисов, размещенных в одном исполняемом файле Windows?

    Как использовать библиотеку moment.js в угловом 2-х машинописном приложении?

    Linux Mint не запускает X автоматически после обновления, но X все еще работает

    Можно ли заставить Java игнорировать «хранилище доверия» и просто принять любой сертификат SSL, который он получает?

    Номер формата как фиксированная ширина, с ведущими нулями

    Проблема с разрешением Windows 7

    Почему AccessViolationException не может быть заражен .NET4.0

    Обновить поле в массиве точного элемента в MongoDB

    Windows 7: не удается привязать приложение к панели задач

    Как установить смещение для ScrollSpy в Bootstrap?

    Как аннулировать сеанс в JSF 2.0?

    Где я должен делать инъекцию с помощью Ninject 2+ (и как я могу упорядочить свои модули?)

    Давайте будем гением компьютера.