[SPRING] Spring : 모든 환경 속성에 Map 또는 Properties 객체로 액세스
SPRINGSpring : 모든 환경 속성에 Map 또는 Properties 객체로 액세스
주석을 사용하여 다음과 같이 스프링 환경을 구성합니다.
@Configuration
...
@PropertySource("classpath:/config/default.properties")
...
public class GeneralApplicationConfiguration implements WebApplicationInitializer
{
@Autowired
Environment env;
}
이것은 환경의 일부인 default.properties의 속성으로 연결됩니다. 환경 설정 (예 : config_dir 위치)에 따라 여러 대체 시스템 계층과 다양한 동적 위치를 통해 속성을 오버로드 할 수있는 기능을 이미 제공하고 있으므로 여기 @PropertySource 메커니즘을 사용하고 싶습니다. 방금 예제를 쉽게 만들기 위해 폴백을 제거했습니다.
그러나 이제는 내 문제는 예를 들어 default.properties에 데이터 소스 속성을 구성하려고합니다. 데이터 소스가 사용할 것으로 예상되는 설정을 자세히 알지 못해도 설정을 데이터 소스에 전달할 수 있습니다.
Properties p = ...
datasource.setProperties(p);
그러나 문제는 Environment 객체가 Properties 객체도 Map도 아니며 비교할 수없는 객체라는 점입니다. 필자가 생각하기에 환경의 모든 값에 접근하는 것은 불가능하다. 왜냐하면 keySet이나 iterator 메소드가 없기 때문이다.
Properties p <=== Environment env?
내가 놓친 게 있니? 어떻게 든 Environment 객체의 모든 항목에 액세스 할 수 있습니까? 그렇다면 엔트리를 Map 또는 Properties 객체에 매핑 할 수 있습니다. 접두어로 필터하거나 매핑 할 수도 있습니다 - 하위 세트를 표준 Java Map으로 만듭니다 ... 이것은 내가하고 싶은 것입니다. 어떤 제안?
해결법
-
==============================
1.당신은 이것과 같은 것이 필요합니다. 아마 이것은 개선 될 수 있습니다. 이것이 첫 번째 시도입니다 :
당신은 이것과 같은 것이 필요합니다. 아마 이것은 개선 될 수 있습니다. 이것이 첫 번째 시도입니다 :
... 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<String, Object> 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 인 환경 (및 구현이 상당히 많음)의 모든 것을 특성 맵으로 액세스 할 수 있습니다.
-
==============================
2.이것은 오래된 질문이지만, 받아 들여진 대답은 심각한 결함이 있습니다. Spring Environment 객체에 오버 라이딩 된 값이 포함되어있는 경우 (Externalized Configuration에 설명 된대로) 생성 된 속성 값의 맵이 Environment 객체에서 반환 된 값과 일치한다는 보장이 없습니다. 환경의 PropertySources를 반복하는 것만으로도 실제로 어떤 중요한 값도 제공하지 않는다는 것을 알았습니다. 대신 원래 값, 즉 재정의되어야 할 값을 생성했습니다.
이것은 오래된 질문이지만, 받아 들여진 대답은 심각한 결함이 있습니다. Spring Environment 객체에 오버 라이딩 된 값이 포함되어있는 경우 (Externalized Configuration에 설명 된대로) 생성 된 속성 값의 맵이 Environment 객체에서 반환 된 값과 일치한다는 보장이 없습니다. 환경의 PropertySources를 반복하는 것만으로도 실제로 어떤 중요한 값도 제공하지 않는다는 것을 알았습니다. 대신 원래 값, 즉 재정의되어야 할 값을 생성했습니다.
여기에 더 나은 해결책이 있습니다. 환경의 EnumerablePropertySources를 사용하여 알려진 속성 이름을 반복하지만 실제 Spring 환경에서 실제 값을 읽습니다. 이렇게하면 값이 대체 값을 포함하여 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::<String>stream) .forEach(propName -> props.setProperty(propName, springEnv.getProperty(propName)));
-
==============================
3.키가 별개의 접두사 (예 : "log4j.appender"로 시작하는 모든 속성)로 시작하는 모든 속성을 검색해야하고 다음 코드 (Java 8의 스트림과 lamdas 사용)를 작성해야합니다.
키가 별개의 접두사 (예 : "log4j.appender"로 시작하는 모든 속성)로 시작하는 모든 속성을 검색해야하고 다음 코드 (Java 8의 스트림과 lamdas 사용)를 작성해야합니다.
public static Map<String,Object> getPropertiesStartingWith( ConfigurableEnvironment aEnv, String aKeyPrefix ) { Map<String,Object> result = new HashMap<>(); Map<String,Object> map = getAllProperties( aEnv ); for (Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); if ( key.startsWith( aKeyPrefix ) ) { result.put( key, entry.getValue() ); } } return result; } public static Map<String,Object> getAllProperties( ConfigurableEnvironment aEnv ) { Map<String,Object> result = new HashMap<>(); aEnv.getPropertySources().forEach( ps -> addAll( result, getAllProperties( ps ) ) ); return result; } public static Map<String,Object> getAllProperties( PropertySource<?> aPropSource ) { Map<String,Object> 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<String, Object> aBase, Map<String, Object> aToBeAdded ) { for (Entry<String, Object> entry : aToBeAdded.entrySet()) { if ( aBase.containsKey( entry.getKey() ) ) { continue; } aBase.put( entry.getKey(), entry.getValue() ); } }
시작 지점은 포함 된 PropertySources를 반환 할 수있는 ConfigurableEnvironment입니다 (ConfigurableEnvironment는 환경의 직계 하위 항목 임). 다음과 같이 autowire 할 수 있습니다.
@Autowired private ConfigurableEnvironment myEnv;
매우 특별한 종류의 속성 소스 (예 : JndiPropertySource)를 사용하지 않는 경우 (일반적으로 봄 자동 구성에서는 사용되지 않음) 환경에 포함 된 모든 속성을 검색 할 수 있습니다.
구현은 스프링 자체가 제공하고 처음 발견 된 속성을 취하는 반복 순서에 의존하며 나중에 발견 된 동일한 이름의 속성은 모두 삭제됩니다. 이것은 환경이 속성에 대해 직접 요청 된 것과 동일한 동작을 보장해야합니다 (발견 된 첫 번째 반환).
또한 $ {...} 연산자로 별칭이 포함 된 경우 반환 된 속성은 아직 해결되지 않았습니다. 특정 키를 확인하려면 환경에 다시 질문해야합니다.
myEnv.getProperty( key );
-
==============================
4.이 봄의 Jira 티켓으로, 이는 의도적 인 디자인입니다. 그러나 다음 코드는 나를 위해 작동합니다.
이 봄의 Jira 티켓으로, 이는 의도적 인 디자인입니다. 그러나 다음 코드는 나를 위해 작동합니다.
public static Map<String, Object> getAllKnownProperties(Environment env) { Map<String, Object> 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; }
-
==============================
5.다른 답변은 PropertySources를 포함하는 대부분의 경우에 대한 해결책을 지적했지만, 특정 속성 소스를 유용한 유형으로 형변환 할 수 없다는 언급은 아직 없습니다.
다른 답변은 PropertySources를 포함하는 대부분의 경우에 대한 해결책을 지적했지만, 특정 속성 소스를 유용한 유형으로 형변환 할 수 없다는 언급은 아직 없습니다.
그러한 예제 중 하나는 명령 줄 인수의 속성 소스입니다. 사용되는 클래스는 SimpleCommandLinePropertySource입니다. 이 private 클래스는 public 메서드에 의해 반환되므로 객체 내부의 데이터에 액세스하는 것은 매우 까다로운 작업입니다. 데이터를 읽고 궁극적으로 속성 소스를 바꾸려면 리플렉션을 사용해야했습니다.
더 나은 해결책을 가진 사람이 있다면 정말보고 싶습니다. 그러나 이것이 내가 일한 유일한 해킹입니다.
-
==============================
6.다음 코드를 시도해보십시오.
다음 코드를 시도해보십시오.
... @Autowired private Environment env; ... for(Iterator<PropertySource<?>> it = ((AbstractEnvironment) env).getPropertySources().iterator(); it.hasNext(); ) { PropertySource<?> propertySource = (PropertySource<?>) it.next(); if (propertySource instanceof CompositePropertySource) { for(Iterator<PropertySource<?>> it2 = ((CompositePropertySource) propertySource).getPropertySources().iterator(); it2.hasNext(); ) { PropertySource<?> propertySource2 = (PropertySource<?>) it2.next(); if (propertySource2 instanceof ResourcePropertySource) { for (Entry<String, Object> entry : ((ResourcePropertySource)propertySource2).getSource().entrySet()) { if (entry.getValue() instanceof String) { System.out.println(entry.getKey() + "=" + (String)entry.getValue()); } } } } } }
-
==============================
7.스프링 부트 2로 작업하면서 비슷한 것을해야했습니다. 위 답변의 대부분은 정상적으로 작동하지만 앱 라이프 사이클의 여러 단계에서 결과가 달라질 수 있음을 명심하십시오.
스프링 부트 2로 작업하면서 비슷한 것을해야했습니다. 위 답변의 대부분은 정상적으로 작동하지만 앱 라이프 사이클의 여러 단계에서 결과가 달라질 수 있음을 명심하십시오.
예를 들어, ApplicationEnvironmentPreparedEvent 다음에 application.properties 내의 모든 특성이 없습니다. 그러나 ApplicationPreparedEvent 이벤트가 발생하면 이벤트가 발생합니다.
-
==============================
8.Spring은 Spring Environment로부터 java.util.Properties를 통해 분리를 허용하지 않습니다.
Spring은 Spring Environment로부터 java.util.Properties를 통해 분리를 허용하지 않습니다.
그러나 Properties.load ()는 여전히 스프링 부트 응용 프로그램에서 작동합니다.
Properties p = new Properties(); try (InputStream is = getClass().getResourceAsStream("/my.properties")) { p.load(is); }
from https://stackoverflow.com/questions/23506471/spring-access-all-environment-properties-as-a-map-or-properties-object by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Log4J를 봄으로 초기화 하시겠습니까? (0) | 2018.12.09 |
---|---|
[SPRING] org.hibernate.proxy.pojo.javassist.Javassist 클래스에 대한 serializer가 없습니다. (0) | 2018.12.09 |
[SPRING] 스프링 부트 : EmbeddedServletContainerFactory 빈이 없어서 EmbeddedWebApplicationContext를 시작할 수 없습니다. (0) | 2018.12.09 |
[SPRING] 스프링 부트의 필터 순서 (0) | 2018.12.09 |
[SPRING] 스프링 주석 기반 구성을 사용하는 동안 MappingJacksonHttpMessageConverter를 구성하는 방법은 무엇입니까? (0) | 2018.12.09 |