IT이야기

Spring Boot: 뚱뚱한 항아리가 있는 임의의 디렉토리에서 외부 application.properties 파일을 사용

cyworld 2021. 10. 7. 21:05
반응형

Spring Boot: 뚱뚱한 항아리가 있는 임의의 디렉토리에서 외부 application.properties 파일을 사용할 수 있습니까?


여러 application.properties 파일을 가질 수 있습니까? ( 편집 : 이 질문은 제목에 있는 질문으로 발전했습니다.)

2개의 파일을 만들려고 했습니다.

  • 첫 번째는 응용 프로그램 Jar의 루트 폴더에 있습니다.
  • 두 번째는 classpath에 지정된 디렉토리에 있습니다.

2개의 파일 이름은 모두 'application.properties'입니다.

두 파일의 내용을 '병합'할 수 있습니까? (그리고 두 번째 속성 값은 첫 번째 속성 값보다 우선합니다.) 아니면 하나의 파일이 있으면 다른 파일은 무시됩니까?

업데이트 1 : 내용을 '병합'할 수 있습니다. 어제는 첫 번째는 무시된 것 같았는데, 그 때 뭔가 깨져서 그런 것 같다. 이제 잘 작동합니다.

업데이트 2 : 다시 돌아왔습니다! 다시 두 파일 중 하나만 적용됩니다. 이상하네요... Spring Tool Suite를 사용하여 앱 jar 파일을 빌드한 후 시작되었습니다. 그리고 Jar 버전은 항상 두 번째 버전(클래스 경로에서)을 무시하는 반면 STS에서 실행되는 확장 버전의 동작은 다양합니다. 어디서부터 조사를 시작할 수 있습니까?

업데이트 3 :

Jar 버전의 동작은 실제로 정확했습니다. java.exe의 사양입니다. -jar 옵션이 지정되면 java.exe는 -classpath 옵션과 CLASSPATH 환경 변수를 모두 무시하고 클래스 경로에는 jar 파일만 포함됩니다. 따라서 클래스 경로의 두 번째 application.properties 파일은 무시됩니다.

이제 클래스 경로의 두 번째 application.properties를 로드하려면 어떻게 해야 합니까?

업데이트 4 :

-jar 옵션을 사용하면서 외부 경로에 application.properties 파일을 로드할 수 있었습니다.

핵심은 PropertiesLauncher였습니다.

PropertiesLauncher를 사용하려면 pom.xml 파일을 다음과 같이 변경해야 합니다.

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>  <!-- added -->
                <layout>ZIP</layout> <!-- to use PropertiesLaunchar -->
            </configuration>
        </plugin>
    </plugins>
</build>

이를 위해 다음 StackOverflow 질문을 참조했습니다. 스프링 부트 속성 런처를 사용할 수 없습니다 . BTW, Spring Boot Maven Plugin 문서( http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html )에는 ZIP 트리거를 지정한다는 언급이 없습니다. PropertiesLauncher가 사용됩니다. (아마도 다른 문서에서?)

jar 파일이 빌드된 후 jar 파일의 META-INF/MENIFEST.MF에서 Main-Class 속성을 검사하여 PropertiesLauncher를 사용하는 것을 확인할 수 있었습니다.

이제 다음과 같이 jar를 실행할 수 있습니다(Windows에서).

java -Dloader.path=file:///C:/My/External/Dir,MyApp-0.0.1-SNAPSHOT.jar -jar MyApp-0.0.1-SNAPSHOT.jar

응용 프로그램 jar 파일은 loader.path에 포함되어 있습니다.

이제 C:\My\External\Dir\config의 application.properties 파일이 로드됩니다.

보너스로 해당 디렉토리의 모든 파일(예: 정적 html 파일)은 로더 경로에 있으므로 jar에서도 액세스할 수 있습니다.

UPDATE 2에서 언급한 non-jar(확장) 버전의 경우 클래스 경로 순서 문제가 있을 수 있습니다.

(BTW, 이 문제에 대해 보다 구체적으로 질문의 제목을 변경했습니다.)


Spring Boot의 기본값을 변경하지 않은 경우(즉 , 속성 소스 처리를 사용 중이 @EnableAutoConfiguration거나 @SpringBootApplication변경하지 않은 경우) 다음 순서로 속성을 찾습니다(가장 높은 값이 가장 낮은 값보다 우선 적용됨).

  1. /config현재 디렉토리 하위 디렉토리
  2. 현재 디렉토리
  3. 클래스 경로 /config 패키지
  4. 클래스 경로 루트

위의 목록 은 문서의 부분에 언급되어 있습니다.

이것이 의미하는 바는 예를 들어 application.properties아래 src/resources에 속성이 있는 경우 패키지된 jar의 "옆에" application.properties있는 /config디렉토리 에서 찾은 동일한 이름을 가진 속성에 의해 무시 된다는 것입니다.

Spring Boot에서 사용하는 이 기본 순서는 매우 쉬운 구성 외부화를 허용하므로 여러 환경(개발, 스테이징, 프로덕션, 클라우드 등)에서 애플리케이션을 쉽게 구성할 수 있습니다.

속성 읽기를 위해 Spring Boot에서 제공하는 전체 기능 세트를 보려면(힌트: 읽는 것보다 훨씬 더 많이 사용 가능 application.properties) 문서의 부분을 확인하십시오 .

위의 짧은 설명이나 전체 문서에서 알 수 있듯이 Spring Boot 앱은 DevOps 친화적입니다!


여기 문서에 모두 설명되어 있습니다.

http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

이것이 우선 순위임을 설명합니다.

  • 현재 디렉토리의 /config 하위 디렉토리.
  • 현재 디렉토리
  • 클래스 경로 /config 패키지
  • 클래스 경로 루트

또한 다음과 같이 재정의를 위해 추가 속성 파일을 정의할 수 있다고 지적합니다.

java -jar myproject.jar 
    --spring.config.location=classpath:/overrides.properties

를 사용하는 경우 에 spring.config.location대한 모든 기본 위치 application.properties도 포함됩니다. 이는 application.properties특정 환경에서 필요에 따라 기본값을 설정 하고 재정의 할 수 있음을 의미 합니다.


-jar 옵션을 사용하면서 외부 경로에 application.properties 파일을 로드할 수 있었습니다.

핵심은 PropertiesLauncher였습니다.

PropertiesLauncher를 사용하려면 pom.xml 파일을 다음과 같이 변경해야 합니다.

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>  <!-- added -->
                <layout>ZIP</layout> <!-- to use PropertiesLaunchar -->
            </configuration>
        </plugin>
    </plugins>
</build>

이를 위해 다음 StackOverflow 질문을 참조했습니다. 스프링 부트 속성 런처를 사용할 수 없습니다 . BTW, Spring Boot Maven Plugin 문서( http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html )에는 ZIP 트리거를 지정한다는 언급이 없습니다. PropertiesLauncher가 사용됩니다. (아마도 다른 문서에서?)

jar 파일이 빌드된 후 jar 파일의 META-INF/MENIFEST.MF에서 Main-Class 속성을 검사하여 PropertiesLauncher를 사용하는 것을 확인할 수 있었습니다.

이제 다음과 같이 jar를 실행할 수 있습니다(Windows에서).

java -Dloader.path=file:///C:/My/External/Dir,MyApp-0.0.1-SNAPSHOT.jar -jar MyApp-0.0.1-SNAPSHOT.jar

응용 프로그램 jar 파일은 loader.path에 포함되어 있습니다.

이제 C:\My\External\Dir\config의 application.properties 파일이 로드됩니다.

보너스로 해당 디렉토리의 모든 파일(예: 정적 html 파일)은 로더 경로에 있으므로 jar에서도 액세스할 수 있습니다.

UPDATE 2에서 언급한 non-jar(확장) 버전의 경우 클래스 경로 순서 문제가 있을 수 있습니다.


다음과 같이 외부 속성 파일 경로를 사용하여 스프링 부트 애플리케이션을 시작할 수 있습니다.

java -jar {jar-file-name}.jar 
--spring.config.location=file:///C:/{file-path}/{file-name}.properties

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <layout>ZIP</layout> 
            </configuration>
        </plugin>
    </plugins>
</build>

java -Dloader.path=file:///absolute_path/external.jar -jar example.jar

이것은 늦게 올 수도 있지만 특히 @PropertySource("classpath:some.properties") 대신 사용하여 스프링 부트 앱을 실행할 때 외부 구성을 로드하는 더 좋은 방법을 java jar myapp.war 찾은 것 같습니다.

구성은 프로젝트의 루트 또는 war/jar 파일이 실행되는 위치에서 로드됩니다.

public class Application implements EnvironmentAware {

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

    @Override
    public void setEnvironment(Environment environment) {
        //Set up Relative path of Configuration directory/folder, should be at the root of the project or the same folder where the jar/war is placed or being run from
        String configFolder = "config";
        //All static property file names here
        List<String> propertyFiles = Arrays.asList("application.properties","server.properties");
        //This is also useful for appending the profile names
        Arrays.asList(environment.getActiveProfiles()).stream().forEach(environmentName -> propertyFiles.add(String.format("application-%s.properties", environmentName))); 
        for (String configFileName : propertyFiles) {
            File configFile = new File(configFolder, configFileName);
            LOGGER.info("\n\n\n\n");
            LOGGER.info(String.format("looking for configuration %s from %s", configFileName, configFolder));
            FileSystemResource springResource = new FileSystemResource(configFile);
            LOGGER.log(Level.INFO, "Config file : {0}", (configFile.exists() ? "FOund" : "Not Found"));
            if (configFile.exists()) {
                try {
                    LOGGER.info(String.format("Loading configuration file %s", configFileName));
                    PropertiesFactoryBean pfb = new PropertiesFactoryBean();
                    pfb.setFileEncoding("UTF-8");
                    pfb.setLocation(springResource);
                    pfb.afterPropertiesSet();
                    Properties properties = pfb.getObject();
                    PropertiesPropertySource externalConfig = new PropertiesPropertySource("externalConfig", properties);
                    ((ConfigurableEnvironment) environment).getPropertySources().addFirst(externalConfig);
                } catch (IOException ex) {
                    LOGGER.log(Level.SEVERE, null, ex);
                }
            } else {
                LOGGER.info(String.format("Cannot find Configuration file %s... \n\n\n\n", configFileName));

            }

        }
    }

}

도움이 되기를 바랍니다.


fat jar(-cp fat.jar) 또는 모든 jar(-cp "$JARS_DIR/*")를 포함하는 클래스 경로와 일반적으로 jar 외부 및 다른 위치에 구성 파일이 포함된 다른 사용자 정의 구성 클래스 경로 또는 폴더를 사용하는 또 다른 유연한 방법입니다. 따라서 제한된 java -jar 대신 다음과 같이보다 유연한 클래스 경로를 사용하십시오.

java \
   -cp fat_app.jar \ 
   -Dloader.path=<path_to_your_additional_jars or config folder> \
   org.springframework.boot.loader.PropertiesLauncher

Spring-boot 실행 가능한 jar 문서이 링크를 참조하십시오.

일반적인 MainApp이 여러 개 있는 경우 실행 가능한 jar에 사용할 기본 클래스를 Spring Boot에 알리는 방법 을 사용할 수 있습니다 .

loader.properties에서 환경 변수 LOADER_PATH 또는 loader.path를 설정하여 추가 위치를 추가할 수 있습니다(아카이브 내의 디렉토리, 아카이브 또는 디렉토리의 쉼표로 구분된 목록). 기본적으로 loader.path는 java -jar 또는 java -cp 방식 모두에서 작동합니다.

그리고 항상 그렇듯이 디버깅 목적으로 선택해야 하는 application.yml을 재정의하고 정확하게 지정할 수 있습니다.

--spring.config.location=/some-location/application.yml --debug

yml 파일에 대한 솔루션:

1. jar 응용 프로그램과 동일한 디렉토리에 yml 복사

2. 명령 실행, 예 xxx.yml:

java -jar app.jar --spring.config.location=xxx.yml

잘 작동하지만 시작 로거에서 INFO:

No active profile set .........

maven 설치를 사용하여 스프링 부트 jar를 생성하고 속성 파일 및 lib 폴더와 같은 모든 리소스를 jar 외부에서 생성하려는 경우 ... 그런 다음 내가 원하는 출력 폴더를 정의하는 pom.xml 내부에 다음 코드를 추가합니다. jar의 원하는 리소스를 추출하고 저장합니다.

<build>
<finalName>project_name_Build/project_name</finalName>
   <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/project_name_Build/lib</outputDirectory>
                        <overWriteReleases>false</overWriteReleases>
                        <overWriteSnapshots>false</overWriteSnapshots>
                        <overWriteIfNewer>true</overWriteIfNewer>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>write here the qualified or complete path of main class of application</mainClass>
                    </manifest>
                    <manifestEntries>
                        <Class-Path>. resources/</Class-Path>
                    </manifestEntries>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>application.properties</include>
                <include>log4j.properties</include>
            </includes>
            <targetPath>${project.build.directory}/ConsentGatewayOfflineBuild/resources</targetPath>
        </resource>

        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>application.properties</include>
                <include>log4j.properties</include>
            </includes>
        </resource>

    </resources>

    <pluginManagement>
        <plugins>
            <!-- Ignore/Execute plugin execution -->
            <plugin>
                <groupId>org.eclipse.m2e</groupId>
                <artifactId>lifecycle-mapping</artifactId>
                <version>1.0.0</version>
                <configuration>
                    <lifecycleMappingMetadata>
                        <pluginExecutions>
                            <!-- copy-dependency plugin -->
                            <pluginExecution>
                                <pluginExecutionFilter>
                                    <groupId>org.apache.maven.plugins</groupId>
                                    <artifactId>maven-dependency-plugin</artifactId>
                                    <versionRange>[1.0.0,)</versionRange>
                                    <goals>
                                        <goal>copy-dependencies</goal>
                                    </goals>
                                </pluginExecutionFilter>
                                <action>
                                    <ignore />
                                </action>
                            </pluginExecution>
                        </pluginExecutions>
                    </lifecycleMappingMetadata>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

나는 그것이 뾰족한 질문이라는 것을 알고 있으며 op는 다른 속성 파일을로드하기를 원했습니다.

내 대답은 이와 같은 맞춤 해킹을 하는 것은 끔찍한 생각이라는 것입니다.

클라우드 파운드리와 같은 클라우드 공급자와 함께 spring-boot를 사용하고 있다면 스스로에게 호의를 베풀고 클라우드 구성 서비스를 사용하십시오

https://spring.io/projects/spring-cloud-config

마술과 같은 default/dev/project-default/project-dev 특정 속성을 로드하고 병합합니다.

다시 말하지만, Spring 부트는 이미 이를 수행할 수 있는 충분한 방법을 제공합니다. https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

바퀴를 재발명하지 마십시오.


java -jar server-0.0.1-SNAPSHOT.jar --spring.config.location=application-prod.properties

ReferenceURL : https://stackoverflow.com/questions/26140784/spring-boot-is-it-possible-to-use-external-application-properties-files-in-arbi

반응형