【问题标题】:Is it possible to have a default application.yml in a custom Spring boot starter?自定义 Spring Boot 启动器中是否可以有默认的 application.yml?
【发布时间】:2020-03-24 08:03:55
【问题描述】:

我的自定义 Spring Boot 启动器和用作依赖项的 Spring Boot 应用程序使用者遇到问题。我在两个 application.yml 中都有,但似乎我正在寻找的配置只有在消费者中定义时才有效。

我在启动器中的配置是这样的:

@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "security")
public class StarterSecurityConfig {
    private boolean jwtEnabled;
    private String[] unsecuredPaths;
    private String[] securedPaths;
}

我在 AutoConfiguration 类中定义了这个 bean:

@Bean
public StarterSecurityConfig starterSecurityConfig() {
    return new StarterSecurityConfig();
}

拥有这个 application.yml 和另一个变量的消费者可以完美地检索到它:

    security:
  jwt-enabled: true
  secured-paths:
    - /user/**
  unsecured-paths:
    - /**

但是如果我从消费者那里删除它并将它放在启动器的 application.yml 中,那么启动器 bean 在创建它们时就没有这些属性。

也许我错过了什么?

【问题讨论】:

  • 我们在这个用例中使用 Spring Cloud Common(引导上下文),如果你不关心你的启动器带来额外的依赖:spring.io/projects/spring-cloud-commons 实际上我们默认启用一些配置文件启用我们的配置,所以团队不必关心例如oauth 设置。

标签: java spring spring-boot


【解决方案1】:

如果我正确理解你的问题,我上周就遇到了这样的问题...... 我正在检查这个问题,我有一些发现(官方文档不支持它们):如果您添加依赖项并想要使用它的资源,那么您会遇到两个 application.yml 文件具有相同位置的情况 - classpath:application.yml,或者它们不能一起加载,或者其中一个被另一个覆盖。无论如何,在我的应用程序中,它不起作用。

如果您只需要从依赖配置文件加载配置,直接而简单的解决方案 - 重命名并以可能的方式加载(从 YAML 手动加载、属性源的初始化程序等)

但是如果这个配置文件应该在任何地方使用,我们可以在上下文中手动加载属性。在依赖项(在您的情况下为消费者)创建另一个配置文件,例如@configuration 类中的 consumer-application.yml 和下一个 bean:

@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
    var propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
    var yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
    yamlPropertiesFactoryBean.setResources(new ClassPathResource("consumer-application.yaml"));
    propertySourcesPlaceholderConfigurer.setProperties(yamlPropertiesFactoryBean.getObject());
    return propertySourcesPlaceholderConfigurer;
}

您可以在两个应用程序中通过 @Value 使用 YAML 文件中的属性。

但最简单的方法 - 使用属性配置。在这种情况下,您只需在消费者中设置@PropertySource("classpath:consumer-application.properties")@PropertySource(value = {"classpath:application.properties", "classpath:consumer-application.properties"}) 在我的情况下,这两种变体都能正常工作。

【讨论】:

  • 感谢您评论德米特里。这个问题是我需要做相反的事情。当消费者有一个时加载 application.yml。我的想法是像你一样做相反的事情。设置为资源 somethink 像 application-starter.yml 并让消费者拥有 application.yml 但它似乎不起作用:/
【解决方案2】:

您可以尝试在启动器本身上初始化成员变量。如果消费者想要覆盖他们可以通过应用程序配置来实现的值。

@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "security")
public class StarterSecurityConfig {
    private boolean jwtEnabled = true;
    private String[] unsecuredPaths = { "/user/**" };
    private String[] securedPaths = { "/**" };
}

还有一些想法:

我会将 jwtEnabled 设为 false,并从上述类中删除 @Configuration 和 @ConfigurationProperties 并使用其他 bean 创建一个 SecurityAutoConfiguration 类。

@Configuration
public class SecurityAutoConfiguration{

   @Bean
   @ConfigurationProperties(prefix = "security")
   public StarterSecurityConfig starterSecurityConfig(){
     return new StarterSecurityConfig();
   }

   @Bean
   @ConditionalOnProperty(value="security.jwtEnabled", havingValue = "true")
   public JwtService jwtService(StarterSecurityConfig starterSecurityConfig) {
     return new JwtService(starterSecurityConfig);
   }   

}

消费者将能够使用 security.jwtEnabled 标志通过其应用程序配置启用或禁用安全启动器。

【讨论】:

  • 嗨,Sam,我已经在 SecurityAutoConfiguration 中有 conditionalOnProperty 并且工作正常。我的问题与启动器的默认 application.yml 有关。如果消费者有另一个 application.yml,则启动器会考虑消费者,没有覆盖。我需要一些启动器中的默认值,比如 spring: jpa: hibernate: ddl-auto: validate。我也尝试过 Dmitry 的方法,但它对我无效,因为我不想在启动器中指定消费者的 yaml
  • 所以如果我理解正确,您不希望消费者覆盖这些值吗?
  • 是的,但消费者不仅覆盖了这些值。如果两者中都有 application.yml ,则删除启动器中存在的所有键。它不仅是压倒一切的,它就像启动器一样,它没有被考虑到
猜你喜欢
  • 2016-03-06
  • 1970-01-01
  • 2014-02-27
  • 1970-01-01
  • 2020-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-24
相关资源
最近更新 更多