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

时间:2014-10-01 11:53:27

标签: spring configuration spring-boot

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

我试过有2个文件。

  • 第一个是应用程序Jar中的根文件夹。
  • 第二个是在classpath中指定的目录。

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

是否可以'合并'两个文件的内容? (并且第二个属性值覆盖第一个属性值)或者,如果我有一个文件,则忽略另一个文件?

更新1 :可以“合并”内容。昨天似乎第一个被忽略了,但似乎是因为当时有些东西被打破了。现在效果很好。

更新2 :又回来了!同样,只应用了两个文件中的一个。这很奇怪......它是在我使用Spring Tool Suite构建app 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问题:spring boot properties launcher unable to use。顺便说一下,在Spring Boot Maven插件文档(http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html)中,没有提到指定使用了PropertiesLauncher的ZIP触发器。 (也许在另一份文件中?)

在构建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文件。

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

对于UPDATE 2中提到的非jar(扩展)版本,可能存在类路径顺序问题。

(顺便说一句,我将问题的标题更改为更具体地解决了这个问题。)

11 个答案:

答案 0 :(得分:42)

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

  1. 当前目录的/config子目录
  2. 当前目录
  3. classpath /config
  4. classpath root
  5. 上面的列表在文档的this部分中提到

    这意味着,如果找到application.properties下的src/resources下的application.properties属性,则会被/configapplication.properties中具有相同名称的属性覆盖}&#34; next&#34;到打包的罐子里。

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

    要查看Spring Boot提供的用于属性读取的整套功能(提示:除了从{{1}}阅读之外还有更多可用的功能),请查看文档的this部分。

    从我上面的简短说明或完整文档中可以看出,Spring Boot应用程序非常适合DevOps!

答案 1 :(得分:16)

这些都在文档中解释:

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

这解释了这是优先顺序:

  • 当前目录的A / config子目录。
  • 当前目录
  • classpath / config包
  • classpath root

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

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

如果您使用spring.config.location,则还会包含application.properties的所有默认位置。这意味着您可以在application.properties中设置默认值,并根据特定环境的要求进行覆盖。

答案 2 :(得分:9)

我设法在使用-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问题:spring boot properties launcher unable to use。顺便说一下,在Spring Boot Maven插件文档(http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html)中,没有提到指定使用了PropertiesLauncher的ZIP触发器。 (也许在另一份文件中?)

在构建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文件。

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

对于UPDATE 2中提到的非jar(扩展)版本,可能存在类路径顺序问题。

答案 3 :(得分:7)

您可以使用外部属性文件路径启动Spring启动应用程序,如下所示:

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

答案 4 :(得分:2)

<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

答案 5 :(得分:0)

这可能会迟到但我认为我找到了一种更好的方法来加载外部配置,尤其是当您使用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)); } } } } 而不是@PropertySource(&#34; classpath)运行spring-boot应用程序时:some.properties&#34)

配置将从项目的根目录或从运行war / jar文件的位置加载

{{1}}

希望它有所帮助。

答案 6 :(得分:0)

使用包含fat jar(-cp fat.jar)或所有jar(-cp&#34; $ JARS_DIR / *&#34;)的类路径和另一个包含配置文件的自定义配置类路径或文件夹的另一种灵活方式外面的罐子。因此,使用更灵活的类路径方式而不是有限的java -jar,如下所示:

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

请参阅Spring-boot executable jar docthis link

如果你有多个常见的MainApp,你可以使用 How do I tell Spring Boot which main class to use for the executable jar?

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

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

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

答案 7 :(得分:0)

yml文件的解决方案:

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

2.运行命令,xxx.yml的示例:

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

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

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

答案 8 :(得分:0)

当您使用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>

答案 9 :(得分:0)

我知道这是一个尖锐的问题,操作人员希望加载其他属性文件。

我的答案是,像这样进行自定义骇客是一个可怕的主意。

如果您要通过Cloud Foundry等云提供商使用spring-boot,请帮帮忙,并使用云配置服务

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

它加载并合并default / dev / project-default / project-dev特定于属性的属性,例如魔术

再次, Spring Boot已经为您提供了足够的方法来正确执行此操作 https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

请不要重新发明轮子。

答案 10 :(得分:0)

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