Spring Boot:是否可以在带有胖 jar 的任意目录中使用外部 application.properties 文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26140784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 00:06:20  来源:igfitidea点击:

Spring Boot: Is it possible to use external application.properties files in arbitrary directories with a fat jar?

springconfigurationspring-boot

提问by zeodtr

Is it possible to have multiple application.properties file? (EDIT: note that this question evolved to the one on the title.)

是否可以有多个 application.properties 文件?(编辑:请注意,这个问题演变为标题上的问题。)

I tried to have 2 files.

我试图有 2 个文件。

  • The first one is on the root folder in the application Jar.
  • The second one is on the directory which is specified in classpath.
  • 第一个位于应用程序 Jar 的根文件夹中。
  • 第二个位于类路径中指定的目录中。

2 files are both named 'application.properties'.

2 个文件都命名为“application.properties”。

Is it possible to 'merge' the contents of both files? (and the second one's property values override the first one's) Or, if I have one file then the other file is ignored?

是否可以“合并”两个文件的内容?(第二个的属性值覆盖第一个的)或者,如果我有一个文件,那么另一个文件将被忽略?

UPDATE 1: it is possible to 'merge' the contents. Yesterday it seemed that the first one was ignored, but it seems that it's because that something was broken then. Now it works well.

更新 1:可以“合并”内容。昨天好像第一个被忽略了,但似乎是因为当时有什么东西坏了。现在它运作良好。

UPDATE 2: It's back again! Again only one of two files is being applied. It's strange... It started after I built the app jar file using Spring Tool Suite. And it seems that the Jar version always ignores the second one (in classpath), while the behavior of the expanded version which runs on STS varies. From where can I start to investigate?

更新2:它又回来了!同样,仅应用了两个文件之一。很奇怪......它是在我使用Spring Tool Suite构建应用程序jar文件之后开始的。而且似乎 Jar 版本总是忽略第二个(在类路径中),而在 STS 上运行的扩展版本的行为各不相同。我可以从哪里开始调查?

UPDATE 3:

更新 3

The behavior of the Jar version was in fact correct. It's the specification of java.exe. When -jar option is specified, java.exe ignores both -classpath option and CLASSPATH environment variable, and the classpath will contain only the jar file. So, the second application.properties file on the classpath is ignored.

Jar 版本的行为实际上是正确的。这是java.exe的规范。当指定 -jar 选项时,java.exe 会忽略 -classpath 选项和 CLASSPATH 环境变量,并且类路径将仅包含 jar 文件。因此,将忽略类路径上的第二个 application.properties 文件。

Now, how can I let the second application.properties on the classpath be loaded?

现在,如何让类路径上的第二个 application.properties 加载?

UPDATE 4:

更新 4

I managed to load an application.properties file in external path while using -jar option.

在使用 -jar 选项时,我设法在外部路径中加载了一个 application.properties 文件。

The key was PropertiesLauncher.

关键是 PropertiesLauncher。

To use PropertiesLauncher, pom.xml file must be changed like this:

要使用 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>

For this, I referenced the following StackOverflow question: spring boot properties launcher unable to use. BTW, In Spring Boot Maven Plugin document(http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html), there is no mention that specifying ZIP triggers that PropertiesLauncher is used. (Perhaps in another document?)

为此,我参考了以下 StackOverflow 问题:spring boot properties launchercannot use. 顺便说一句,在 Spring Boot Maven 插件文档(http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html)中,没有提到指定 ZIP 触发器使用 PropertiesLauncher。(也许在另一个文件中?)

After the jar file had been built, I could see that the PropertiesLauncher is used by inspecting Main-Class property in META-INF/MENIFEST.MF in the jar.

在构建 jar 文件后,我可以通过检查 jar 中 META-INF/MENIFEST.MF 中的 Main-Class 属性看到使用 PropertiesLauncher。

Now, I can run the jar as follows(in Windows):

现在,我可以按如下方式运行 jar(在 Windows 中):

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

Note that the application jar file is included in loader.path.

请注意,应用程序 jar 文件包含在 loader.path 中。

Now an application.properties file in C:\My\External\Dir\config is loaded.

现在 C:\My\External\Dir\config 中的 application.properties 文件已加载。

As a bonus, any file (for example, static html file) in that directory can also be accessed by the jar since it's in the loader path.

作为奖励,该目录中的任何文件(例如,静态 html 文件)也可以被 jar 访问,因为它位于加载程序路径中。

As for the non-jar (expanded) version mentioned in UPDATE 2, maybe there was a classpath order problem.

至于UPDATE 2中提到的非jar(扩展)版本,可能是classpath顺序问题。

(BTW, I changed the question's title to be more specific to this issue.)

(顺便说一句,我更改了问题的标题以更具体地针对此问题。)

采纳答案by zeodtr

I managed to load an application.properties file in external path while using -jar option.

在使用 -jar 选项时,我设法在外部路径中加载了一个 application.properties 文件。

The key was PropertiesLauncher.

关键是 PropertiesLauncher。

To use PropertiesLauncher, pom.xml file must be changed like this:

要使用 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>

For this, I referenced the following StackOverflow question: spring boot properties launcher unable to use. BTW, In Spring Boot Maven Plugin document(http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html), there is no mention that specifying ZIP triggers that PropertiesLauncher is used. (Perhaps in another document?)

为此,我参考了以下 StackOverflow 问题:spring boot properties launchercannot use. 顺便说一句,在 Spring Boot Maven 插件文档(http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html)中,没有提到指定 ZIP 触发器使用 PropertiesLauncher。(也许在另一个文件中?)

After the jar file had been built, I could see that the PropertiesLauncher is used by inspecting Main-Class property in META-INF/MENIFEST.MF in the jar.

在构建 jar 文件后,我可以通过检查 jar 中 META-INF/MENIFEST.MF 中的 Main-Class 属性看到使用 PropertiesLauncher。

Now, I can run the jar as follows(in Windows):

现在,我可以按如下方式运行 jar(在 Windows 中):

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

Note that the application jar file is included in loader.path.

请注意,应用程序 jar 文件包含在 loader.path 中。

Now an application.properties file in C:\My\External\Dir\config is loaded.

现在 C:\My\External\Dir\config 中的 application.properties 文件已加载。

As a bonus, any file (for example, static html file) in that directory can also be accessed by the jar since it's in the loader path.

作为奖励,该目录中的任何文件(例如,静态 html 文件)也可以被 jar 访问,因为它位于加载程序路径中。

As for the non-jar (expanded) version mentioned in UPDATE 2, maybe there was a classpath order problem.

至于UPDATE 2中提到的非jar(扩展)版本,可能是classpath顺序问题。

回答by geoand

If you have not changed the defaults of Spring Boot (meaning you are using @EnableAutoConfigurationor @SpringBootApplicationand have not changed any Property Source handling), then it will look for properties with the following order (highest overrides lowest):

如果您尚未更改 Spring Boot 的默认值(意味着您正在使用@EnableAutoConfiguration或未@SpringBootApplication更改任何 Property Source 处理),那么它将按以下顺序查找属性(最高覆盖最低):

  1. A /configsubdir of the current directory
  2. The current directory
  3. A classpath/configpackage
  4. The classpath root
  1. 一个/config当前目录下的子目录
  2. 当前目录
  3. 一个类路径/config
  4. 类路径根

The list above is mentioned in thispart of the documentation

上面的列表在文档的这一部分中提到

What that means is that if a property is found for example application.propertiesunder src/resourcesis will be overridden by a property with the same name found in application.propertiesin the /configdirectory that is "next" to the packaged jar.

这也就意味着,如果一个属性被发现例如application.propertiessrc/resourcesIS将被覆盖由具有相同名称的属性中发现application.properties/config是“下一个”被包装罐子目录。

This default order used by Spring Boot allows for very easy configuration externalization which in turn makes applications easy to configure in multiple environments (dev, staging, production, cloud etc)

Spring Boot 使用的默认顺序允许非常简单的配置外部化,这反过来又使应用程序易于在多种环境(开发、暂存、生产、云等)中配置

To see the whole set of features provided by Spring Boot for property reading (hint: there is a lot more available than reading from application.properties) check out thispart of the documentation.

要查看 Spring Boot 提供的用于属性读取的整套功能(提示:可用的功能远多于读取application.properties),请查看文档的这一部分。

As one can see from my short description above or from the full documentation, Spring Boot apps are very DevOps friendly!

从我上面的简短描述或完整文档中可以看出,Spring Boot 应用程序对 DevOps 非常友好!

回答by Steve

It's all explained here in the docs:

这一切都在文档中进行了解释:

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

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

Which explains that this is the order of precedence:

这解释了这是优先顺序:

  • A /config subdir of the current directory.
  • The current directory
  • A classpath /config package
  • The classpath root
  • 当前目录的 /config 子目录。
  • 当前目录
  • 一个类路径 /config 包
  • 类路径根

It also points out that you can define additional properties files for overrides like so:

它还指出,您可以为覆盖定义其他属性文件,如下所示:

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

If you use spring.config.location, then all the default locations for application.propertiesare also included. This means that you can set up default values in application.propertiesand override as required for a particular environment.

如果使用spring.config.location,则application.properties还包括 的所有默认位置。这意味着您可以根据application.properties特定环境的需要设置和覆盖默认值。

回答by kk.

You would be able to launch your spring boot appication with the external properties file path as follows:

您将能够使用外部属性文件路径启动您的 Spring Boot 应用程序,如下所示:

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

回答by Ravindranath Akila

<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

回答by HimalayanCoder

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

回答by kisna

Another flexible way using classpath containing fat jar (-cp fat.jar) or all jars (-cp "$JARS_DIR/*") and another custom config classpath or folder containing configuration files usually elsewhere and outside jar. So instead of the limited java -jar, use the more flexible classpath way as follows:

另一种灵活的方法是使用包含 fat jar (-cp fat.jar) 或所有 jars (-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

See Spring-boot executable jar docand this link

请参阅Spring-boot 可执行文件 jar 文档此链接

If you do have multiple MainApps which is common, you can use How do I tell Spring Boot which main class to use for the executable jar?

如果您确实有多个常见的 MainApps,您可以使用 How do I tell Spring Boot 哪个主类用于可执行 jar?

You can add additional locations by setting an environment variable LOADER_PATH or loader.path in loader.properties (comma-separated list of directories, archives, or directories within archives). Basically loader.path works for both java -jar or java -cp way.

您可以通过在 loader.properties(以逗号分隔的目录、档案或档案中的目录的列表)中设置环境变量 LOADER_PATH 或 loader.path 来添加其他位置。基本上 loader.path 适用于 java -jar 或 java -cp 方式。

And as always you can override and exactly specify the application.yml it should pickup for debugging purpose

和往常一样,您可以覆盖并准确指定 application.yml 它应该为调试目的而选择

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

回答by Piotr R

Solution for yml file:

yml文件解决方法:

1.Copy yml to in same directory that jar application

1. 将 yml 复制到 jar 应用程序的同一目录中

2.Run command, example for xxx.yml:

2.运行命令,例如xxx.yml

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

It's works fine, but in startup logger is INFO:

它工作正常,但在启动记录器中是 INFO:

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

回答by PulkitRajput

When you are creating spring boot jar using maven install and you want all the resources like properties file and lib folder to be created outside of jar ...then add the following code inside pom.xml where i am defining the output folder where i want to extract and store the desired resources of jar.

当您使用 maven install 创建 spring boot jar 并且您希望在 jar 之外创建所有资源(如属性文件和 lib 文件夹)时……然后在 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>

回答by Kalpesh Soni

I know it is a pointed question, and the op wanted to load different properties file.

我知道这是一个尖锐的问题,并且操作员想要加载不同的属性文件。

My answer is, doing custom hacks like this is a terrible idea.

我的回答是,像这样自定义 hack 是一个糟糕的主意。

If you are using spring-boot with a cloud provider such as cloud foundry, please do yourself a favor and use cloud config services

如果你在云代工厂等云提供商上使用 spring-boot,请帮自己一个忙,使用云配置服务

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

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

It loads and merges default/dev/project-default/project-dev specific properties like magic

它加载并合并 default/dev/project-default/project-dev 特定属性,如魔法

Again, Spring boot already gives you enough ways to do this right https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

同样,Spring Boot 已经为您提供了足够的方法来做到这一点 https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

Please do not re-invent the wheel.

请不要重新发明轮子。