如何在Spring中继承application.properties配置文件?

25
如果我创建了一个包含常见配置的application.properties的公共库,例如:

spring.main.banner-mode=off

我如何将这些属性继承到另一个包含该公共库的项目中?

Maven:

<project ...>
    <groupId>de.mydomain</groupId>
    <artifactId>my-core</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <!-- this one holds the common application.properties -->
            <groupId>my.domain</groupId>
            <artifactId>my-commons</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>
</project>

我怎样才能将my-commons的配置继承到my-core中?


1
我认为你不应该继承属性。在我看来,这太冒险了。如果你仔细想想,如果你从两个不同的依赖项中继承相同的属性会发生什么?你如何检测这些冲突? - Mickael
那么,我该如何添加应用于所有项目的配置呢?假设我想定义一个公司范围的公共项目,设置例如使用Logger,一个常见的MailSender,xml配置等。从中继承的每个项目都应强制使用此配置...另外,spring-boot本身以某种方式管理它来定义默认属性。它们甚至可以被覆盖。但是他们是如何实现这一点的呢? - membersound
@membersound,你得到答案了吗? - soorapadman
你是指下面这个吗?是的,但是没起作用。 - membersound
你使用Spring-Boot创建了一个库,并使用了application.properties吗?要包含在项目中的库是一些静态的东西,不能独立启动。因此,你不应该采用这种方法。否则,你可以将库(项目)本身直接包含到主项目中。当然,这只是我的个人意见。 - Lazar Lazarov
3个回答

20

解决方案是使用不同的名称包含共享属性,这里使用application-shared.properties

在共享库中:

@SpringBootApplication
@PropertySource(ResourceUtils.CLASSPATH_URL_PREFIX + "application-shared.properties") //can be overridden by application.properties
public class SharedAutoConfiguration {
}

在主应用程序中:

@SpringBootApplication
@Import(SharedAutoConfiguration.class)
public class MainAppConfiguration extends SpringBootServletInitializer {

}

这种方式可以加载共享配置,但是仍然可以在主应用程序的application.properties中进行覆盖。

它与 spring.main.banner-mode 属性不兼容(不知道为什么),但对于所有其他属性都可以正常工作。


4
请注意,这仅适用于.properties文件,而不适用于.yml文件。https://dev59.com/TJ7ha4cB1Zd3GeqPn8D0#41984422 - Richard Tingle
1
根据最新的Spring Boot文档,"请注意,此类属性源在应用程序上下文刷新之前不会被添加到环境中。这太晚了,无法配置某些属性,例如logging.*和spring.main.*,它们在刷新开始之前被读取。" - dansomething

1

我有同样的动机——将典型服务的常见配置提取到单独的启动器/库中。我决定使用EnvironmentPostProcessor

我的commons-web库有自己的application-web.properties,其中有一个属性,比如说:

spring.main.banner-mode: off

并且需要一个EnvironmentPostProcessor来获取它

public class DefaultPropertiesEnvironmentPostProcessor implements EnvironmentPostProcessor {

  @SneakyThrows
  @Override
  public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
    environment.getPropertySources()
        .addLast(new ResourcePropertySource("application-web.properties"));
  }

}

为了使其工作,您需要在resources/META-INF/spring.factories中指定一个后处理器(在库端)。具体操作如下:
org.springframework.boot.env.EnvironmentPostProcessor=\
     com.surprise.starter.web.properties.DefaultPropertiesEnvironmentPostProcessor

通过这种解决方案,可以在服务端获取此配置并在常规的application.properties中覆盖它。


我没有使用@PropertySource,因为存在属性排序和检测上的细微差别

...

请在@Configuration类上使用@PropertySource注释。请注意,此类属性源在应用程序上下文刷新之前不会添加到环境中。这太晚了,不能配置某些属性,例如logging.*和spring.main.*,这些属性在刷新开始之前就被读取了。


0
你可以尝试使用Spring实现此操作。
你可以像你所提到的那样,在一个公共模块中定义你的src/main/resources/application.properties文件。它将存在于其他依赖于此模块的项目的类路径中。
然后,在依赖于公共模块的其他项目中,使用注解@PropertySource
@Configuration
@PropertySource("classpath*:META-INF/spring/properties/*.properties")
public class Config {
  ...
}

或者使用 XML 配置:

<context:property-placeholder location="classpath*:META-INF/spring/properties/*.properties"/>

它应该导入给定类路径目录中的所有配置文件。

此外,您应该注意不能在类路径中有两个相同的文件。否则会发生冲突。

例如,以下情况将生成冲突

项目A(依赖于项目B):

  • src/main/resources/application.properties

项目 B:

  • src/main/resources/application.properties

您需要重命名application.properties文件或将其放置在不同的目录中。


你的解决方案对于这种情况是有效的。如果属性存在于资源文件中,只需要说 classpath*:spring/application.properties 即可。 - soorapadman
我在我的commons项目中尝试了如下代码:@PropertySource("classpath:application-commons.properties")。但是它没有起作用,spring-banner仍然被打印出来(这意味着属性没有被加载)。 - membersound

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接