주석을 사용하여 다음과 같이 스프링 환경을 구성합니다.
@Configuration
...
@PropertySource("classpath:/config/default.properties")
...
public class GeneralApplicationConfiguration implements WebApplicationInitializer
{
@Autowired
Environment env;
}
이로 인해 내 속성 default.properties
이 Environment
. @PropertySource
환경 설정 (예 : config_dir 위치)에 따라 여러 폴백 레이어와 다른 동적 위치를 통해 속성을 오버로드 할 수있는 가능성을 이미 제공하기 때문에 여기 에서 메커니즘 을 사용하고 싶습니다 . 예제를 더 쉽게 만들기 위해 대체를 제거했습니다.
그러나 내 문제는 예를 들어 내 데이터 소스 속성을 default.properties
. 데이터 소스가 사용하는 데 필요한 설정을 자세히 알지 않고도 데이터 소스에 설정을 전달할 수 있습니다.
Properties p = ...
datasource.setProperties(p);
그러나 문제는 Environment
객체가 Properties
객체도 Map
아니고 비교할만한 것도 아니라는 것입니다. 전혀 없기 때문에 내 관점에서 환경의 모든 값에 액세스 할 단순히 수 없습니다 keySet
또는 iterator
방법 또는 유사한 아무것도.
Properties p <=== Environment env?
내가 뭔가를 놓치고 있습니까? Environment
어떻게 든 객체 의 모든 항목에 액세스 할 수 있습니까? 그렇다면 항목을 Map
또는 Properties
객체에 매핑 할 수 있으며 접두사로 필터링하거나 매핑 할 수도 있습니다. 하위 집합을 표준 자바로 생성합니다 Map
. 이것이 제가하고 싶은 일입니다. 어떤 제안?
답변
이와 같은 것이 필요합니다. 아마도 개선 될 수 있습니다. 이것은 첫 번째 시도입니다.
...
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
(그리고 상당히 많은 구현이 있음) Map
은 속성 으로 액세스 할 수 있습니다 .
답변
이것은 오래된 질문이지만 받아 들여지는 대답에는 심각한 결함이 있습니다. Spring Environment
객체가 ( Externalized Configuration에 설명 된대로) 재정의 값을 포함하는 경우, 생성하는 속성 값의 맵이 Environment
객체 에서 반환 된 값과 일치 할 것이라는 보장이 없습니다 . 나는 단순히의 PropertySource
s를 반복하는 것이 Environment
실제로 어떤 재정의 값도 제공하지 않는다는 것을 발견했습니다 . 대신에 재정의되어야하는 원래 값을 생성했습니다.
여기에 더 나은 해결책이 있습니다. 이것은의 EnumerablePropertySource
s Environment
를 사용하여 알려진 속성 이름을 반복하지만 실제 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)));
답변
키가 고유 한 접두어로 시작하는 모든 속성 (예 : “log4j.appender.”로 시작하는 모든 속성)을 검색하고 다음 코드 (Java 8의 스트림 및 람다 사용)를 작성해야했습니다.
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() );
}
}
시작점은 포함 된 PropertySource를 반환 할 수있는 ConfigurableEnvironment입니다 (ConfigurableEnvironment는 Environment의 직계 하위 항목입니다). 다음과 같이 자동 배선 할 수 있습니다.
@Autowired
private ConfigurableEnvironment myEnv;
매우 특별한 종류의 속성 소스 (예 : 스프링 자동 구성에서 일반적으로 사용되지 않는 JndiPropertySource)를 사용하지 않는 경우 환경에있는 모든 속성을 검색 할 수 있습니다.
구현은 스프링 자체가 제공하는 반복 순서에 의존하고 처음 발견 된 속성을 취하며 나중에 발견 된 동일한 이름의 모든 속성은 삭제됩니다. 이렇게하면 환경이 속성을 직접 요청한 것과 동일한 동작을 보장해야합니다 (첫 번째 발견 된 속성 반환).
또한 반환 된 속성은 $ {…} 연산자가있는 별칭을 포함하는 경우 아직 확인되지 않습니다. 특정 키를 확인하려면 환경에 직접 다시 문의해야합니다.
myEnv.getProperty( key );
답변
원래 질문은 접두사를 기반으로 모든 속성을 필터링 할 수 있으면 좋을 것임을 암시했습니다. 나는 이것이 Spring Boot 2.1.1.RELEASE에서 Properties
또는 Map<String,String>
. 나는 그것이 당분간 작동했다고 확신합니다. 흥미롭게도, 그것이없는 것은 작업을 수행 prefix =
자격, 내가 할 즉 하지 얻가하는 방법을 알고 전체 지도에로드 환경을. 내가 말했듯이 이것은 실제로 OP가 시작하고 싶었던 것일 수 있습니다. 접두사 및 다음 ‘.’ 원할 수도 있고 아닐 수도 있습니다.
@ConfigurationProperties(prefix = "abc")
@Bean
public Properties getAsProperties() {
return new Properties();
}
@Bean
public MyService createService() {
Properties properties = getAsProperties();
return new MyService(properties);
}
포스트 스크립트 : 전체 환경을 얻는 것이 실제로 가능하고 부끄럽게 쉽습니다. 이것이 어떻게 나를 탈출했는지 모르겠습니다.
@ConfigurationProperties
@Bean
public Properties getProperties() {
return new Properties();
}
답변
이번 봄의 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;
}
답변
Spring은 java.util.Properties
Spring Environment에서 분리하는 것을 허용하지 않습니다 .
그러나 Properties.load()
여전히 스프링 부트 애플리케이션에서 작동합니다.
Properties p = new Properties();
try (InputStream is = getClass().getResourceAsStream("/my.properties")) {
p.load(is);
}
답변
다른 답변은 PropertySources
.
이러한 예 중 하나는 명령 줄 인수의 속성 소스입니다. 사용되는 클래스는 SimpleCommandLinePropertySource
입니다. 이 private 클래스는 public 메서드에 의해 반환 되므로 개체 내부의 데이터에 액세스하는 것이 매우 까다로워집니다. 데이터를 읽고 결국 속성 소스를 교체하기 위해 리플렉션을 사용해야했습니다.
누구든지 더 나은 솔루션을 가지고 있다면 정말보고 싶습니다. 그러나 이것은 내가 작업 한 유일한 해킹입니다.