[java] Spring Boot 및 여러 외부 구성 파일

클래스 경로에서로드하려는 여러 속성 파일이 있습니다. 의 /src/main/resources일부인 기본 세트가 하나 있습니다 myapp.jar. 내 springcontext파일이 클래스 경로에있을 것으로 예상합니다. 즉

<util:properties id="Job1Props"
    location="classpath:job1.properties"></util:properties>

<util:properties id="Job2Props"
    location="classpath:job2.properties"></util:properties>

또한 이러한 속성을 외부 집합으로 재정의하는 옵션이 필요합니다. 에 외부 구성 폴더가 cwd있습니다. 스프링 부트 문서 구성 폴더에 따라 클래스 경로에 있어야합니다. 그러나 applicaiton.properties거기에서 또는 config의 모든 속성을 재정의하는 경우 문서에서 명확하지 않습니다 .

내가 그것을 테스트했을 때만 application.properties선택되고 나머지 속성은 여전히 /src/main/resources. 쉼표로 구분 된 목록으로 제공하려고 시도 spring.config.location했지만 기본 집합은 여전히 ​​재정의되지 않습니다.

여러 외부 구성 파일이 기본 구성 파일을 무시하도록하려면 어떻게해야합니까?

해결 방법으로 현재 app.config.location명령 줄을 통해 제공하는 (앱 특정 속성)을 사용했습니다 . 즉

java -jar myapp.jar app.config.location=file:./config

그리고 나는 나의 변화 applicationcontext에를

<util:properties id="Job2Props"
    location="{app.config.location}/job2.properties"></util:properties>

그리고 이것이 Application을로드하는 동안 파일과 클래스 경로를 분리하는 방법입니다.
편집 :

//psuedo code

if (StringUtils.isBlank(app.config.location)) {
            System.setProperty(APP_CONFIG_LOCATION, "classpath:");
}

위의 해결 방법을 사용하지 않고 파일과 마찬가지로 클래스 경로의 모든 외부 구성 파일을 봄이 재정의하도록하고 싶습니다 application.properties.



답변

Spring Boot를 사용할 때 속성은 다음 순서로로드됩니다 ( Spring Boot 참조 가이드의 Externalized Configuration 참조).

  1. 명령 줄 인수.
  2. 자바 시스템 속성 (System.getProperties ()).
  3. OS 환경 변수.
  4. java : comp / env의 JNDI 속성
  5. random. *에 속성 만있는 RandomValuePropertySource입니다.
  6. 패키지 된 jar 외부의 애플리케이션 속성 (YAML 및 프로필 변형을 포함한 application.properties)
  7. jar 내부에 패키징 된 애플리케이션 속성 (YAML 및 프로필 변형을 포함한 application.properties).
  8. @Configuration 클래스의 @PropertySource 주석.
  9. 기본 속성 (SpringApplication.setDefaultProperties를 사용하여 지정됨).

속성을 확인할 때 (즉, @Value("${myprop}")확인은 역순으로 수행됩니다 (따라서 9로 시작).

다른 파일을 추가하려면 spring.config.location쉼표로 구분 된 속성 파일 목록 또는 파일 위치 (디렉터리)를 사용하는 속성을 사용할 수 있습니다 .

-Dspring.config.location=your/config/dir/

위의 application.properties파일 은 파일을 참조 할 디렉토리를 추가 합니다.

-Dspring.config.location=classpath:job1.properties,classpath:job2.properties

로드 된 파일에 2 개의 속성 파일이 추가됩니다.

기본 구성 파일 및 위치는 추가로 지정된 spring.config.location항목 보다 먼저로드 됩니다. 즉, 후자는 항상 이전 항목에 설정된 속성을 재정의합니다. ( Spring Boot Reference Guide 의이 섹션 도 참조하십시오 ).

spring.config.location디렉토리 (파일과 반대)가 포함 된 경우 /로 끝나야합니다 ( spring.config.name로드되기 전에 생성 된 이름이 추가됩니다 ). 의 classpath:,classpath:/config,file:,file:config/값에 관계없이 기본 검색 경로 가 항상 사용됩니다 spring.config.location. 이러한 방식으로 애플리케이션의 기본값을에서 application.properties(또는으로 선택한 다른 기본 이름 spring.config.name) 설정하고 런타임에 기본값을 유지하면서 다른 파일로 재정의 할 수 있습니다 .

업데이트 : spring.config.location의 동작이 이제 기본값을 추가하는 대신 재정의합니다. 기본값을 유지하려면 spring.config.additional-location을 사용해야합니다. 이것은 1.x에서 2.x 로의 동작 변경입니다.


답변

Spring boot를 사용하면 spring.config.location이 작동하며 쉼표로 구분 된 속성 파일 만 제공합니다.

아래 코드를 참조하십시오

@PropertySource(ignoreResourceNotFound=true,value="classpath:jdbc-${spring.profiles.active}.properties")
public class DBConfig{

     @Value("${jdbc.host}")
        private String jdbcHostName;
     }
}

응용 프로그램에 jdbc.properties의 기본 버전을 넣을 수 있습니다. 외부 버전은 이것으로 설정할 수 있습니다.

java -jar target/myapp.jar --spring.config.location=classpath:file:///C:/Apps/springtest/jdbc.properties,classpath:file:///C:/Apps/springtest/jdbc-dev.properties

spring.profiles.active 속성을 사용하여 설정 한 프로필 값에 따라 jdbc.host 값이 선택됩니다. 그래서 언제 (윈도우에서)

set spring.profiles.active=dev

jdbc.host는 jdbc-dev.properties에서 값을 가져옵니다.

…에 대한

set spring.profiles.active=default

jdbc.host는 jdbc.properties에서 값을 가져옵니다.


답변

Spring Boot 1.X 및 Spring Boot 2.X는 Externalized Configuration.

M. Deinum의 좋은 대답은 Spring Boot 1 사양을 나타냅니다.
여기서 Spring Boot 2를 업데이트하겠습니다.

환경 속성 소스 및 순서

Spring Boot 2는 PropertySource합리적인 값 재정의를 허용하도록 설계된 매우 특별한 순서를 사용합니다. 속성은 다음 순서로 고려됩니다.

  • 홈 디렉토리의 Devtools 전역 설정 속성 (devtools가 활성화 된 경우 ~ / .spring-boot-devtools.properties).

  • @TestPropertySource 테스트에 대한 주석.

  • @SpringBootTest#properties테스트의 주석 속성. 명령 줄 인수.

  • 속성 SPRING_APPLICATION_JSON(환경 변수 또는 시스템 속성에 포함 된 인라인 JSON).

  • ServletConfig 초기화 매개 변수.

  • ServletContext 초기화 매개 변수.

  • JNDI는에서 속성 java:comp/env.

  • Java System 속성 ( System.getProperties()).

  • OS 환경 변수.

  • RandomValuePropertySource랜덤으로 만 속성이 있는 A. *.

  • 패키지 된 jar ( application-{profile}.properties및 YAML 변형) 외부의 프로필 별 애플리케이션 속성 .

  • jar ( application-{profile}.properties및 YAML 변형) 내에 패키징 된 프로필 별 애플리케이션 속성 .

  • 패키지 된 jar ( application.properties및 YAML 변형) 외부의 애플리케이션 속성 .

  • jar ( application.properties및 YAML 변형) 내에 패키지 된 애플리케이션 속성 .

  • @PropertySource@Configuration수업 에 대한 주석 . 기본 속성 (설정으로 지정됨
    SpringApplication.setDefaultProperties).

외부 속성 파일을 지정하려면 이러한 옵션이 중요합니다.

  • 패키지 된 jar ( application-{profile}.properties및 YAML 변형) 외부의 프로필 별 애플리케이션 속성 .

  • 패키지 된 jar ( application.properties및 YAML 변형) 외부의 애플리케이션 속성 .

  • @PropertySource@Configuration수업 에 대한 주석 . 기본 속성 (설정으로 지정됨
    SpringApplication.setDefaultProperties).

이 세 가지 옵션 중 하나만 사용하거나 요구 사항에 따라 조합 할 수 있습니다.
예를 들어 매우 간단한 경우에는 프로필 별 속성 만 사용하는 것으로 충분하지만 다른 경우에는 프로필 별 속성, 기본 속성 및 @PropertySource.

application.properties 파일의 기본 위치

에 대한 application.properties기본 봄로드 그들과 다음과 같은 순서로 이들의 환경에서 자신의 속성을 추가하여 파일 (및 변형) :

  • 현재 디렉토리의 / config 하위 디렉토리

  • 현재 디렉토리

  • 클래스 경로 / config 패키지

  • 클래스 경로 루트

더 높은 우선 순위는 말 그대로 :
classpath:/,classpath:/config/,file:./,file:./config/.

특정 이름을 가진 속성 파일을 사용하는 방법은 무엇입니까?

기본 위치가 항상 충분하지는 않습니다. 기본 파일 이름 ( application.properties) 과 같은 기본 위치 는 적합하지 않을 수 있습니다. 게다가 OP 질문에서와 같이 application.properties(및 변형) 이외의 여러 구성 파일을 지정해야 할 수도 있습니다 .
그래서 spring.config.name충분하지 않을 것입니다.

이 경우 spring.config.location환경 속성 (쉼표로 구분 된 디렉터리 위치 또는 파일 경로 목록)을 사용하여 명시 적 위치를 제공해야합니다 .
파일 이름 패턴에 대한 자유를 얻으려면 디렉토리 목록보다 파일 경로 목록을 선호하십시오.
예를 들어 다음과 같이하십시오.

java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

이 방법은 폴더를 지정하는 것보다 가장 장황하지만 구성 파일을 매우 세밀하게 지정하고 효과적으로 사용되는 속성을 명확하게 문서화하는 방법이기도합니다.

spring.config.location은 이제 기본 위치를 추가하는 대신 대체합니다.

Spring Boot 1에서 spring.config.location인수는 Spring 환경에서 지정된 위치를 추가합니다.
그러나 Spring Boot 2에서는 문서에spring.config.location 명시된대로 Spring 환경의 지정된 위치에서 Spring이 사용하는 기본 위치를 대체합니다 .

를 사용하여 사용자 지정 구성 위치를 구성
spring.config.location하면 기본 위치가 대체됩니다. 예를 들어,이 spring.config.location값으로 설정되어
classpath:/custom-config/, file:./custom-config/검색 순서는 다음이된다 :

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.location이제 모든 application.properties파일이 명시 적으로 지정되어야 하는지 확인하는 방법 입니다. 파일
을 패키징하지 않는 우버 JAR의 경우에는 application.properties다소 좋습니다.

spring.config.locationSpring Boot 2를 사용하는 동안 의 이전 동작을 유지하려면 문서에 명시된대로 위치 추가하는 spring.config.additional-location대신 새 속성을 사용할 수 있습니다 .spring.config.location

또는를 사용하여 사용자 지정 구성 위치를 구성
spring.config.additional-location하면 기본 위치와 함께 사용됩니다.


실제로

따라서 OP 질문에서와 같이 지정할 외부 속성 파일 2 개와 uber jar에 포함 된 속성 파일 1 개가 있다고 가정합니다.

지정한 구성 파일 만 사용하려면 다음을 수행하십시오.

-Dspring.config.location=classpath:/job1.properties,classpath:/job2.properties,classpath:/applications.properties   

기본 위치에 구성 파일을 추가하려면 다음을 수행하십시오.

-Dspring.config.additional-location=classpath:/job1.properties,classpath:/job2.properties

classpath:/applications.properties 마지막 예에서는 기본 위치에 필요하지 않으며 기본 위치는 여기에서 덮어 쓰지 않고 확장됩니다.


답변

PropertyPlaceholderConfigurer를 살펴보면 주석보다 사용하는 것이 더 명확합니다.

예 :

@Configuration
public class PropertiesConfiguration {


    @Bean
    public PropertyPlaceholderConfigurer properties() {
        final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
//        ppc.setIgnoreUnresolvablePlaceholders(true);
        ppc.setIgnoreResourceNotFound(true);

        final List<Resource> resourceLst = new ArrayList<Resource>();

        resourceLst.add(new ClassPathResource("myapp_base.properties"));
        resourceLst.add(new FileSystemResource("/etc/myapp/overriding.propertie"));
        resourceLst.add(new ClassPathResource("myapp_test.properties"));
        resourceLst.add(new ClassPathResource("myapp_developer_overrides.properties")); // for Developer debugging.

        ppc.setLocations(resourceLst.toArray(new Resource[]{}));

        return ppc;
    }


답변

이것은 스프링 부트를 사용하는 하나의 간단한 접근법입니다.

TestClass.java

@Configuration
@Profile("one")
@PropertySource("file:/{selected location}/app.properties")
public class TestClass {

    @Autowired
    Environment env;

    @Bean
    public boolean test() {
        System.out.println(env.getProperty("test.one"));
        return true;
    }
}

선택한 위치app.properties 컨텍스트

test.one = 1234

당신의 봄 부팅 응용 프로그램

@SpringBootApplication

public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(testApplication.class, args);
    }
}

및 사전 정의 된 application.properties 컨텍스트

spring.profiles.active = one

원하는만큼 많은 구성 클래스를 작성하고 spring.profiles.active = 프로필 이름 / 이름 {쉼표로 구분} 를 설정하여 활성화 / 비활성화 할 수 있습니다.

스프링 부트가 훌륭하다는 것을 알 수 있듯이 언젠가는 익숙해 지기만하면됩니다. 필드에서도 @Value를 사용할 수 있다는 점을 언급 할 가치가 있습니다.

@Value("${test.one}")
String str;


답변

나는 같은 문제가 있었다. Spring Boot application.properties 감지와 유사한 외부 파일로 시작시 내부 구성 파일을 덮어 쓸 수있는 기능을 원했습니다. 제 경우에는 애플리케이션 사용자가 저장되는 user.properties 파일입니다.

내 요구 사항 :

다음 위치에서 파일을로드합니다 (이 순서대로).

  1. 클래스 경로
  2. 현재 디렉토리 의 / config 하위 디렉토리.
  3. 현재 디렉토리
  4. 시작시 명령 줄 매개 변수에 의해 제공된 디렉토리 또는 파일 위치에서

다음 해결책을 찾았습니다.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.Properties;

import static java.util.Arrays.stream;

@Configuration
public class PropertiesConfig {

    private static final Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);

    private final static String PROPERTIES_FILENAME = "user.properties";

    @Value("${properties.location:}")
    private String propertiesLocation;

    @Bean
    Properties userProperties() throws IOException {
        final Resource[] possiblePropertiesResources = {
                new ClassPathResource(PROPERTIES_FILENAME),
                new PathResource("config/" + PROPERTIES_FILENAME),
                new PathResource(PROPERTIES_FILENAME),
                new PathResource(getCustomPath())
        };
        // Find the last existing properties location to emulate spring boot application.properties discovery
        final Resource propertiesResource = stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .reduce((previous, current) -> current)
                .get();
        final Properties userProperties = new Properties();

        userProperties.load(propertiesResource.getInputStream());

        LOG.info("Using {} as user resource", propertiesResource);

        return userProperties;
    }

    private String getCustomPath() {
        return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + PROPERTIES_FILENAME;
    }

}

이제 응용 프로그램은 클래스 경로 리소스를 사용하지만 다른 지정된 위치에서도 리소스를 확인합니다. 존재하는 마지막 자원이 선택되고 사용됩니다. 내 보트를 떠 다니는 속성 위치를 사용하기 위해 java -jar myapp.jar –properties.location = / directory / myproperties.properties로 내 앱을 시작할 수 있습니다.

여기에 중요한 세부 정보 : 속성이 설정되지 않은 경우 오류를 방지하기 위해 @Value 주석의 properties.location에 대한 기본값으로 빈 문자열을 사용합니다.

properties.location의 규칙은 다음과 같습니다. properties.location으로 속성 파일에 대한 디렉터리 또는 경로를 사용합니다.

특정 속성 만 재정의하려는 경우 setIgnoreResourceNotFound (true)가있는 PropertiesFactoryBean을 위치로 설정된 리소스 배열과 함께 사용할 수 있습니다.

이 솔루션은 여러 파일을 처리하도록 확장 할 수 있습니다.

편집하다

여기 여러 파일에 대한 내 솔루션 🙂 이전과 마찬가지로 이것은 PropertiesFactoryBean과 결합 될 수 있습니다.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;

import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;

@Configuration
class PropertiesConfig {

    private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
    private final static String[] PROPERTIES_FILENAMES = {"job1.properties", "job2.properties", "job3.properties"};

    @Value("${properties.location:}")
    private String propertiesLocation;

    @Bean
    Map<String, Properties> myProperties() {
        return stream(PROPERTIES_FILENAMES)
                .collect(toMap(filename -> filename, this::loadProperties));
    }

    private Properties loadProperties(final String filename) {
        final Resource[] possiblePropertiesResources = {
                new ClassPathResource(filename),
                new PathResource("config/" + filename),
                new PathResource(filename),
                new PathResource(getCustomPath(filename))
        };
        final Resource resource = stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .reduce((previous, current) -> current)
                .get();
        final Properties properties = new Properties();

        try {
            properties.load(resource.getInputStream());
        } catch(final IOException exception) {
            throw new RuntimeException(exception);
        }

        LOG.info("Using {} as user resource", resource);

        return properties;
    }

    private String getCustomPath(final String filename) {
        return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + filename;
    }

}


답변

스프링 부트를 사용하면 다양한 환경에 대해 작성하기 위해 다른 프로필을 작성할 수 있습니다. 예를 들어 프로덕션, qa 및 로컬 환경에 대해 별도의 속성 파일을 가질 수 있습니다.

내 로컬 컴퓨터에 따른 구성이있는 application-local.properties 파일은

spring.profiles.active=local

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=users
spring.data.mongodb.username=humble_freak
spring.data.mongodb.password=freakone

spring.rabbitmq.host=localhost
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.port=5672

rabbitmq.publish=true

마찬가지로 application-prod.properties 및 application-qa.properties를 원하는만큼 많은 속성 파일을 작성할 수 있습니다.

그런 다음 다른 환경에서 응용 프로그램을 시작하는 스크립트를 작성하십시오.

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod