【问题标题】:How to externalize Spring Boot application.properties to tomcat/lib folder如何将 Spring Boot application.properties 外部化到 tomcat/lib 文件夹
【发布时间】:2015-09-10 02:17:14
【问题描述】:

我需要一个免费的、可部署的war,myapp1.war,它可以从tomcat/lib 文件夹中检索配置文件。 因为我在同一个 Tomcat 上共存了其他 Web 应用程序:myapp2.war、myapp3.war,所以我需要这个布局:

tomcat/lib/myapp1/application.properties
tomcat/lib/myapp2/application.properties
tomcat/lib/myapp3/application.properties

这样我可以在没有任何属性文件的情况下构建war文件并部署在任何服务器上。

我已阅读Spring documentation,但它解释了如何在作为 jar 运行时设置位置:

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

对于多个共存的战争文件,我无法弄清楚如何做到这一点。

我想知道这是否可能,或者我应该放弃 Spring Boot 并回到传统的 Spring MVC 应用程序。

【问题讨论】:

  • 如何设置spring.config.location 属性并不重要。可以是系统变量或环境变量。甚至可以是 JNDI 或 servlet 上下文。所以它不一定是你的罐子的论据。但是,您可能不想使用application.properties,而是给文件另一个名称,而不是每个应用程序都有自己的目录。然后,您可以简单地从默认的全局设置位置加载它。

标签: java tomcat spring-boot maven-3


【解决方案1】:

一种解决方案可能是将 application-{profile}.properties 加载为 @PropertySource 注释,正如 question 所建议的那样,但随后日志系统将无法工作,正如您在 documentation 中看到的那样。

日志系统在应用程序生命周期的早期初始化 并且在属性文件中找不到这样的日志记录属性 通过@PropertySource 注解加载。

这意味着您在 application-{profiles}.properties 中的日志记录属性如下:

logging.config=classpath:myapp1/logback.xml
logging.path = /path/to/logs
logging.file = myapp1.log

将被忽略,日志系统将无法工作。

为了解决这个问题,我在配置应用程序时使用 SpringApplicationBuilder.properties() 方法在开始时加载属性。在那里我设置了 Spring Boot 使用的“spring.config.location”来加载所有应用程序-{profiles}.properties:

public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder springApplicationBuilder) {
        return springApplicationBuilder
                .sources(Application.class)
                .properties(getProperties());
    }

    public static void main(String[] args) {

        SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder(Application.class)
                .sources(Application.class)
                .properties(getProperties())
                .run(args);
    }

   static Properties getProperties() {
      Properties props = new Properties();
      props.put("spring.config.location", "classpath:myapp1/");
      return props;
   }
}

然后我将属性文件从 src/main/resources 移动到 src/main/resources/myapp1

.
├src
| └main
|   └resources
|     └myapp1
|       └application.properties
|       └application-development.properties
|       └logback.xml
└─pom.xml

在 pom.xml 中,我必须将嵌入式 tomcat 库的范围设置为“提供”。 另外,要从最终战争中排除 src/main/resources/myapp1 中的所有属性文件,并生成一个免配置、可部署的战争:

    <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
            <packagingExcludes>
              **/myapp1/
            </packagingExcludes>
        </configuration>
    </plugin>

然后在Tomcat中我有

├apache-tomcat-7.0.59
 └lib
   ├─myapp1
   |  └application.properties        
   |  └logback.xml
   └─myapp2
     └application.properties
     └logback.xml

现在我可以生成配置免费战争并将其放入 apache-tomcat-7.0.59/webapps 文件夹中。属性文件将使用类路径解析,独立于每个 webapp:

   apache-tomcat-7.0.59/lib/myapp1
   apache-tomcat-7.0.59/lib/myapp2
   apache-tomcat-7.0.59/lib/myapp3

【讨论】:

  • 非常有帮助的答案。但是,无论我做什么,我似乎都无法让 Spring 在 myapp1 文件夹中看到 logback.xml,即使我设置了 logging.config=classpath:myapp1/logback.xml,它也会忽略它。你找到解决办法了吗?
  • @ChrisGeo 你在 apache-tomcat-7.x.xx/lib/myapp1 里面有什么?您是否检查过生成的战争中没有 application.properties 文件?
  • @DanielMora 我尝试使用您在此处给出的相同代码。但它不起作用,不知道我在配置中错过了什么。作为一个罐子,它运行良好,但在部署为战争时失败了。我收到此异常>>>>> java.io.FileNotFoundException:无法打开类路径资源[application.properties],因为它不存在>>>>> 不知道如何解决此问题,请云帮帮我..
  • 谢谢!解决了我最初的问题并帮助我了解 Spring-Boot-Apps-as-WARs 和带有嵌入式 Tomcat 的独立 Jars 之间的区别。
  • 我觉得值得注意的是“总是使用默认的搜索路径classpath:,classpath:/config,file:,file:config/,不管spring.config.location的值如何”来自documentation
【解决方案2】:

在 Linux 服务器上使用 Spring 4.2 和 @Annotation 配置和 tomcat

在你的 Application 类中设置 @PropertySource 像这样:

@Configuration
@EnableWebMvc
@PropertySource(value = { "classpath:application-yourapp.properties"})
@ComponentScan(basePackages = "com.yourapp")
public class YourAppWebConfiguration extends WebMvcConfigurerAdapter {

    ...
}

现在您只需在类路径中包含属性文件

生产中

在 tomcat 上部署你的 .war 文件(或任何东西),并将你的 application-yourapp.properties 放在你的生产机器上。 (例如在 /opt/applyconfigfolder/application-yourapp.properties 中)

然后在你的tomcat(这里是tomcat 7)中打开bin\catalina.sh

你有这条线

# Ensure that any user defined CLASSPATH variables are not used on startup,
# but allow them to be specified in setenv.sh, in rare case when it is needed.
CLASSPATH=

只需添加包含 application.properties 的文件夹的路径

CLASSPATH=:/opt/applyconfigfolder

如果你已经定义了一些类路径,你可以添加它

CLASSPATH=:/opt/applyconfigfolder:/yourpath1:/yourpath2:

我没有尝试过windows,但我认为没有问题

在开发中(使用 eclipse)

├src
| └main
|   └ ....
└config
| └application-yourapp.properties

而不是src/main/resources/application-yourapp.properties

现在在 Eclipse 中将您的配置文件夹添加到类路径,转到您的 tomcat 服务器(或等效)的“运行配置”并将文件夹配置添加到用户条目

好的,你的 application.properties 不在应用程序中,你的项目在开发环境中运行完美。

【讨论】:

  • 而不是改变bin/catalina.sh:更喜欢附加到文件bin\catalina.sh(如果它还不存在则创建)。 echo 'CLASSPATH=$CLASSPATH:/opt/applyconfigfolder' &gt;&gt; "$CATALINA_BASE/bin/setenv.sh"
  • 更正:我的意思是说“更喜欢追加到文件$CATALINA_BASE/bin/setenv.sh".
【解决方案3】:

Daniel Mora 提供了一个很好的解决方案,但您可以使用 spring.config.name (https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files) 代替 spring.config.location,因此您可以在同一个 tomcat/lib 目录中为不同的 Web 应用程序拥有不同的属性文件:

    public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder springApplicationBuilder) {
        return springApplicationBuilder
                .sources(Application.class)
                .properties(getProperties());
    }
    public static void main(String[] args) {

        SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder(Application.class)
                .sources(Application.class)
                .properties(getProperties())
                .run(args);
    }

   static Properties getProperties() {
      Properties props = new Properties();
      props.put("spring.config.name", "myapp1");
      return props;
   }
}

我认为 lib 目录是用于第三方库的,而不是用于存储 Web 应用程序的配置属性。 所以我认为更好的解决方案是使用 conf/catalina.properties 中的 shared.loader 属性添加一个外部文件夹作为附加类路径文件夹:

shared.loader=${catalina.base}/shared/configurations

您可以将您的应用程序属性 app1.properties、app2.properties、ecc.. 放在 apache-tomcat-7.0.59/shared/configurations 中。

在找到覆盖 SpringBootServletInitializer 的配置方法的 Daniel Mora 解决方案之前,我的解决方案是在 src/main/webapp/META-INF 中添加一个带有以下内容的 context.xml:

<Context>
    <Environment name="spring.config.name" value="myapp1" type="java.lang.String" override="false" description="define the property file for srping boot application"/>
</Context>

【讨论】:

  • 使用spring.config.name 的一个潜在缺点是捆绑属性优先于外部属性文件,因此无法从外部覆盖内置属性。使用 spring.config.location 或更好的是,spring.config.alternate-location 允许属性覆盖,因为提供的位置优先。
  • 为什么你说捆绑的属性优先于外部属性文件?你能举个例子吗?谢谢
猜你喜欢
  • 2014-08-09
  • 2017-10-16
  • 2021-05-17
  • 2015-06-26
  • 1970-01-01
  • 2017-05-18
  • 2017-11-24
  • 2015-11-27
  • 1970-01-01
相关资源
最近更新 更多