programing

Spring 프로필에서 @PropertySources를 선택할 수 있습니까?

lovejava 2023. 9. 1. 20:20

Spring 프로필에서 @PropertySources를 선택할 수 있습니까?

Spring 3.1이 있습니다.@Configuration.foo콩을 만드는 것.은 속은다정니다됩에 .defaults.properties 그나 속의재수있다니의 될 수 .overrides.properties 프로그램에 된 응용프에활상있는경우가가 있는 override스프링 프로필.

오버라이드가 없다면 코드는 이렇게 보일 것이고 작동할 것입니다.

@Configuration
@PropertySource("classpath:defaults.properties")
public class MyConfiguration {

    @Autowired
    private Environment environment;

    @Bean
    public Bean bean() {
        ...
        // this.environment.getRequiredProperty("foo");
        ...
    }
}

나는 원합니다.@PropertySource위해서classpath:overrides.properties…에 @Profile("overrides")이것이 어떻게 달성될 수 있는지에 대해 생각해 본 사람이 있습니까?한 옵션 된 옵션이 .@ConfigurationDRY 입니다.ConfigurableEnvironment하지만 어디에 있는지는 잘 모르겠습니다.environment.getPropertySources.addFirst()전화가 끊겼습니다.

을 배치하는 로 직접 을 주입할 때 합니다.@Value하지만 사용할 때는 그렇지 않습니다.Environment 리고그고.getRequiredProperty()방법.

<context:property-placeholder ignore-unresolvable="true" location="classpath:defaults.properties"/>

<beans profile="overrides">
    <context:property-placeholder ignore-unresolvable="true" order="0"
                                  location="classpath:overrides.properties"/>
</beans>

갱신하다

지금 이 작업을 수행하려면 Spring Boot의 YAML 지원, 특히 'Properties 대신 YAML 사용' 섹션을 확인하십시오.프로필 지원을 통해 이 질문이 화제가 될 수 있지만, 그렇지 않습니다.@PropertySource아직 지지하지 않습니다.

순위를 합니다.@PropertySource정적인 내면의 계급에서.그러나 모든 속성 소스를 함께 지정해야 합니다. 즉, "재지정" 대신 "기본" 프로파일을 생성해야 합니다.

@Configuration
public class MyConfiguration
{
    @Configuration
    @Profile("default")
    @PropertySource("classpath:defaults.properties")
    static class Defaults
    { }

    @Configuration
    @Profile("override")
    @PropertySource({"classpath:defaults.properties", "classpath:overrides.properties"})
    static class Overrides
    {
        // nothing needed here if you are only overriding property values
    }

    @Autowired
    private Environment environment;

    @Bean
    public Bean bean() {
        ...
        // this.environment.getRequiredProperty("foo");
        ...
    }
}

두 개의 파일을 정의할 것을 제안합니다. 두 번째 파일은 프로파일을 접미사로 지정한 선택 사항입니다.

@Configuration
@PropertySources({
        @PropertySource("classpath:/myconfig.properties"),
        @PropertySource(value = "classpath:/myconfig-${spring.profiles.active}.properties", ignoreResourceNotFound = true)
})
public class MyConfigurationFile {

    @Value("${my.prop1}")
    private String prop1;

    @Value("${my.prop2}")
    private String prop2;

}

할 수 있는 일:

  <context:property-placeholder location="classpath:${spring.profiles.active}.properties" />

편집: 고급 기능이 필요한 경우 응용 프로그램을 시작할 때 속성 소스를 등록할 수 있습니다.

web.xml

  <context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>com.xxx.core.spring.properties.PropertySourcesApplicationContextInitializer</param-value>
  </context-param>

생성하는 파일:

public class PropertySourcesApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

  private static final Logger LOGGER = LoggerFactory.getLogger(PropertySourcesApplicationContextInitializer.class);

  @Override
  public void initialize(ConfigurableApplicationContext applicationContext) {
    LOGGER.info("Adding some additional property sources");
    String[] profiles = applicationContext.getEnvironment().getActiveProfiles()
    // ... Add property sources according to selected spring profile 
    // (note there already are some property sources registered, system properties etc)
    applicationContext.getEnvironment().getPropertySources().addLast(myPropertySource);
  }

}

작업을 완료한 후에는 컨텍스트에 다음과 같이 추가하면 됩니다.

<context:property-placeholder/>

여러 프로필에 대한 당신의 질문에 대답할 수는 없지만, 그런 이니셜라이저에서 프로필을 활성화하고 프로필 활성화 중에 적절한 PropertySource 항목을 등록할 수 있습니다.

저는 당신이 에머슨에게 제안한 방법 외에는 다른 방법이 없습니다. 그것은 이 콩을 별도로 정의하는 것입니다.@Configuration@Profile주석:

@Configuration
@Profile("override")
@PropertySource("classpath:override.properties")
public class OverriddenConfig {

    @Autowired
    private Environment environment;

    @Bean
    public Bean bean() {
        //if..
    }
}

여러 프로파일을 지원해야 하는 경우 다음과 같은 작업을 수행할 수 있습니다.

@Configuration
public class Config {

    @Configuration
    @Profile("default")
    @PropertySource("classpath:application.properties")
    static class DefaultProperties {
    }

    @Configuration
    @Profile("!default")
    @PropertySource({"classpath:application.properties", "classpath:application-${spring.profiles.active}.properties"})
    static class NonDefaultProperties {
    }
}

이렇게 하면 각 프로필에 대해 정적 구성 클래스를 정의할 필요가 없습니다.데이비드 하크니스가 저를 올바른 방향으로 이끌어 주셔서 감사합니다.

참고: 이 답변은 속성 파일을 사용할 수 있는 대체 솔루션을 제공합니다.@PropertySource중복 코드를 피하면서 각각 오버라이드가 있을 수 있는 여러 속성 파일을 작업하는 것이 너무 번거로워서 이 경로를 선택했습니다.

관련된 각 속성 집합에 대한 POJO 인터페이스를 만들어 이름과 유형을 정의합니다.

public interface DataSourceProperties
{
    String driverClassName();
    String url();
    String user();
    String password();
}

기본값을 반환하려면 구현합니다.

public class DefaultDataSourceProperties implements DataSourceProperties
{
     public String driverClassName() { return "com.mysql.jdbc.Driver"; }
     ...
}

각 프로파일에 대한 하위 클래스(예: 개발, 생산)를 지정하고 기본값과 다른 값을 재정의합니다.이렇게 하려면 상호 배타적인 프로파일 집합이 필요하지만 "재지정" 대신 "기본값"을 쉽게 추가할 수 있습니다.

@Profile("production")
@Configuration
public class ProductionDataSourceProperties extends DefaultDataSourceProperties
{
     // nothing to override as defaults are for production
}

@Profile("development")
@Configuration
public class DevelopmentDataSourceProperties extends DefaultDataSourceProperties
{
     public String user() { return "dev"; }
     public String password() { return "dev"; }
}

마지막으로 속성 구성을 필요한 다른 구성으로 자동 배선합니다.여기서 장점은 당신이 어떤 것도 반복하지 않는다는 것입니다.@Bean생성 코드.

@Configuration
public class DataSourceConfig
{
    @Autowired
    private DataSourceProperties properties;

    @Bean
    public DataSource dataSource() {
        BoneCPDataSource source = new BoneCPDataSource();
        source.setJdbcUrl(properties.url());
        ...
        return source;
    }
}

서블릿 컨텍스트 이니셜라이저의 활성 프로필을 기반으로 속성 파일을 수동으로 구성하는 것에 대해 여전히 이 문제를 고수할지 확신할 수 없습니다.수동 구성을 하는 것이 유닛 테스트에 적합하지 않을 것이라고 생각했는데, 지금은 잘 모르겠습니다.저는 속성 접근자 목록보다 속성 파일을 읽는 것을 정말 좋아합니다.

여기에 언급된 솔루션은 모두 약간 어색하며, 하나의 프로필 사전 설정에서만 작동하며 더 많은/다른 프로필에서는 작동하지 않습니다.현재 Spring 은 이 기능의 도입을 거부하고 있습니다.하지만 제가 찾은 해결 방법은 다음과 같습니다.

package com.example;

public class MyPropertySourceFactory implements PropertySourceFactory, SpringApplicationRunListener {

    public static final Logger logger = LoggerFactory.getLogger(MyPropertySourceFactory.class);

    @NonNull private static String[] activeProfiles = new String[0];

    // this constructor is used for PropertySourceFactory
    public MyPropertySourceFactory() {
    }

    // this constructor is used for SpringApplicationRunListener
    public MyPropertySourceFactory(SpringApplication app, String[] params) {
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        activeProfiles = environment.getActiveProfiles();
    }

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
        logger.info("Loading: {} with profiles: {}", encodedResource.toString(), activeProfiles);
        // here you know all profiles and have the source Resource with main
        // properties, just try to load other resoures in the same path with different 
        // profile names and return them as a CompositePropertySource
    }
}

그것을 작동시키기 위해서는 당신이 가지고 있어야 합니다.src/main/resources/META-INF/spring.factories다음 내용을 포함합니다.

org.springframework.boot.SpringApplicationRunListener=com.example.MyPropertySourceFactory

이제 사용자 지정 속성 파일을 어딘가에 저장하고 로드할 수 있습니다.@PropertySources:

@Configuration
@PropertySource(value = "classpath:lib.yml", factory = MyPropertySourceFactory.class)
public class PropertyLoader {
}

언급URL : https://stackoverflow.com/questions/12691812/can-propertysources-be-chosen-by-spring-profile