programing

맵 또는 속성 개체로 모든 환경 속성에 액세스

nicegoodjob 2023. 4. 4. 22:54
반응형

맵 또는 속성 개체로 모든 환경 속성에 액세스

주석을 사용하여 스프링 환경을 다음과 같이 구성합니다.

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

.default.properties의 일부인 모양Environment사용하고 싶다.@PropertySource이 메커니즘은 이미 환경 설정(예를 들어 config_module location)에 따라 여러 폴백레이어 및 다른 동적 로케이션을 통해 속성을 오버로드할 수 있는 가능성을 제공하기 때문입니다.그냥 예시를 좀 더 쉽게 하려고 폴백을 벗겼을 뿐이에요.

현재의 는, , 「」의 데이터 소스 을 「」로 하는 것입니다.default.properties. 가 기대하는 알 수 에서 데이터 을 전달할 수 있습니다.

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

는 '이러다'라는 EnvironmentProperties 반대도 아니다Map비교할 만한 것도 없어요.에서는 환경의할 수 있는 은 결코 . 환경에는 환경이라는 것이 때문이다. 왜냐하면 환경에는 아무런 가치도 없기 때문입니다.keySet ★★★★★★★★★★★★★★★★★」iterator방법이나 그에 필적하는 것.

Properties p <=== Environment env?

가가뭘 ?놓 ??? 할 수 있나요?Environment대할할 수??? the a a a a if 、 if 、 if 、 if 、 if 。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 If the Spring (스프링 If the 스프링)Environment오브젝트에는 덮어쓰기 값이 포함되어 있습니다('외부 설정' 참조).이 맵이 생성되는 속성 값의 맵이 에서 반환된 값이 일치한다는 보장은 없습니다.Environment이렇게 단순반복된다는 을 알 수 있었습니다.PropertySourceEnvironment이치노대신 재정의되어야 할 원래 값을 생성합니다.

여기 더 나은 해결책이 있습니다.은 「」를 합니다.EnumerablePropertySourceEnvironment기존 속성 이름을 반복하지만 실제 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의 스트림과 lamda 사용)를 작성해야 했습니다.

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

시작점은 내장된 속성 소스를 반환할 수 있는 구성 가능 환경(구성 가능 환경은 환경의 직계 하위 항목)입니다.다음의 방법으로 자동 접속할 수 있습니다.

@Autowired
private ConfigurableEnvironment  myEnv;

매우 특별한 종류의 속성 소스(일반적으로 스프링 자동 구성에서는 사용되지 않는 JndiPropertySource 등)를 사용하지 않는 경우 환경에 저장된 모든 속성을 검색할 수 있습니다.

이 구현은 스프링 자체가 제공하는 반복 순서에 의존하여 처음 발견된 속성을 가져오고 나중에 동일한 이름을 가진 모든 속성은 폐기됩니다.이것에 의해, 환경에 직접 속성을 요구하는 경우와 같은 동작이 보증됩니다(최초로 발견된 속성을 되돌립니다).

또한 ${...}의 별칭이 포함된 경우 반환된 속성은 아직 해결되지 않습니다.} 연산자.특정 키를 해결하려면 환경에 다시 직접 문의해야 합니다.

myEnv.getProperty( key );

첫 번째 질문에서는 프레픽스를 기반으로 모든 속성을 필터링할 수 있으면 좋겠다고 제안했습니다.스프링 부트 2.1.1.RELEASE, 「」, 「」의 Properties or or or openicle. Map<String,String> 그것은 미있 the, the the the the the the the the the the the the the the the the the the the the the the the the the the 가 없으면 작동하지 않는다.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();
}

이번 봄의 지라 티켓은 의도적인 디자인입니다.하지만 다음 코드가 좋습니다.

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

java.util.Properties봄 환경 environment ★★★

★★★★★★★★★★★★★★★★★.Properties.load()합니다.

Properties p = new Properties();
try (InputStream is = getClass().getResourceAsStream("/my.properties")) {
    p.load(is);
}

은 대부분의 에 대한 하고 있다.PropertySources단, 특정 속성 소스를 유용한 유형으로 주조할 수 없다는 사실은 아무도 언급하지 않았습니다.

이러한 예 중 하나가 명령줄 인수의 속성 소스입니다. 클래스는 「 」입니다.SimpleCommandLinePropertySource이 프라이빗 클래스는 퍼블릭 메서드에 의해 반환되므로 오브젝트 내의 데이터에 액세스하는 것이 매우 까다롭습니다.데이터를 읽고 최종적으로 속성 소스를 대체하기 위해 반사를 사용해야 했습니다.

만약 누군가가 더 나은 해결책을 가지고 있다면, 나는 그것을 꼭 보고 싶다. 하지만 이것은 내가 할 수 있는 유일한 해킹이다.

Spring Boot 2와 함께 작업하면서 비슷한 작업을 해야 했습니다.위의 답변의 대부분은 정상적으로 동작합니다.단, 앱 라이프 사이클의 다양한 단계에서 결과가 다르다는 점에 주의해 주십시오.

를 들어, 예들, 음음, 음 a, 음,ApplicationEnvironmentPreparedEvent application.properties존재하지 않습니다. '' 에 ''가 붙습니다.ApplicationPreparedEvent만약 그들이 있다면.

Spring Boot의 경우 승인된 응답은 우선순위가 낮은 중복 속성을 덮어씁니다.이 솔루션은 속성을 수집합니다.SortedMap우선순위가 가장 높은 중복 속성만 가져옵니다.

final SortedMap<String, String> sortedMap = new TreeMap<>();
for (final PropertySource<?> propertySource : env.getPropertySources()) {
    if (!(propertySource instanceof EnumerablePropertySource))
        continue;
    for (final String name : ((EnumerablePropertySource<?>) propertySource).getPropertyNames())
        sortedMap.computeIfAbsent(name, propertySource::getProperty);
}

한 가지 방법을 더 추가하려고 했어요.을 저저우 this에 .com.hazelcast.config.XmlConfigBuilder한 것은 「」입니다.java.util.Properties의 몇 가지 , Hazelcast XML을 호출하는 은 Hazelcast XML의 「」뿐입니다.getProperty(String)그래서 제가필요을 할 수 되었습니다.

@RequiredArgsConstructor
public class SpringReadOnlyProperties extends Properties {

  private final org.springframework.core.env.Environment delegate;

  @Override
  public String getProperty(String key) {
    return delegate.getProperty(key);
  }

  @Override
  public String getProperty(String key, String defaultValue) {
    return delegate.getProperty(key, defaultValue);
  }

  @Override
  public synchronized String toString() {
    return getClass().getName() + "{" + delegate + "}";
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    if (!super.equals(o)) return false;
    SpringReadOnlyProperties that = (SpringReadOnlyProperties) o;
    return delegate.equals(that.delegate);
  }

  @Override
  public int hashCode() {
    return Objects.hash(super.hashCode(), delegate);
  }

  private void throwException() {
    throw new RuntimeException("This method is not supported");
  }

  //all methods below throw the exception

  * override all methods *
}

P.S. XML 파일의 속성만 해결되고 런타임에는 해결되지 않기 때문에 헤이즐캐스트 전용으로 사용하지 않게 되었습니다.도 봄을 하고 있기 에 '.org.springframework.cache.interceptor.AbstractCacheResolver#getCacheNames캐시 이름에 속성을 사용하는 경우 두 가지 상황 모두에서 속성이 해결됩니다.

에 되어 있는hibernate.properteies 삭제:

@PropertySource(SomeClass.HIBERNATE_PROPERTIES)
public class SomeClass {

  public static final String HIBERNATE_PROPERTIES = "hibernate.properties";

  @Autowired
  private Environment env;

  public void someMethod() {
    final Properties hibProps = asProperties(HIBERNATE_PROPERTIES);
  }

  private Properties asProperties(String fileName) {
    return StreamSupport.stream(
      ((AbstractEnvironment) env).getPropertySources().spliterator(), false)
      .filter(ps -> ps instanceof ResourcePropertySource)
      .map(ps -> (ResourcePropertySource) ps)
      .filter(rps -> rps.getName().contains(fileName))
      .collect(
        Properties::new,
        (props, rps) -> props.putAll(rps.getSource()),
        Properties::putAll);
  }
}

속성의 출처를 분석하는 작은 도우미입니다.이 토론은 SpringConfigurableEnvironment.java를 github에 쓰는 데 사용되었습니다.

테스트에 사용할 수 있습니다.

@SpringBootTest
public class SpringConfigurableEnvironmentTest {
    @Autowired
    private ConfigurableEnvironment springEnv;

    @Test
    public void testProperties() {
        SpringConfigurableEnvironment properties = new SpringConfigurableEnvironment(springEnv);
        SpringConfigurableEnvironment.PropertyInfo info = properties.get("profile.env");
        assertEquals("default", properties.get(info.getValue());
        assertEquals(
           "Config resource 'class path resource [application.properties]' via location 'optional:classpath:/'", 
           info.getSourceList.get(0));
    }
}

위의 모든 답변에는 거의 모든 내용이 포함되지만 환경변수에서 오버라이드된 값은 주의해야 합니다.키 값이 다를 수 있습니다.

를 들어,가 " " "를 덮어쓰는 "my.property[1].value 사용방법MY_PROPERTY[1]_VALUE , 을 통해 합니다.EnumerablePropertySources.getPropertyNames() 다 줄 수 있다my.property[1].value ★★★★★★★★★★★★★★★★★」MY_PROPERTY[1]_VALUE요한값값 값값값다다

것은 이 일이 일어난다면my.property[1].value되어 있지 않습니다.applications.conf (오류)applications.ymla ), a.MY_PROPERTY[1]_VALUE에서는 '이러다'가 .my.property[1].value 다다 but butMY_PROPERTY[1]_VALUE 값( 「」)EnumerablePropertySources.getPropertyNames().

따라서 환경변수로부터 이러한 속성을 커버하는 것은 개발자의 일입니다.안타깝게도 환경 변수 스키마와 일반 스키마 사이에는 일대일 매핑이 없습니다.의 소스 코드를 참조하십시오. 예를 들어,MY_PROPERTY[1]_VALUE 중 하나일 수 .my.property[1].value ★★★★★★★★★★★★★★★★★」my-property[1].value

언급URL : https://stackoverflow.com/questions/23506471/access-all-environment-properties-as-a-map-or-properties-object

반응형