【问题标题】:Multiple yml files configuring in corresponding Configuration class (Spring Boot)在对应的Configuration类中配置多个yml文件(Spring Boot)
【发布时间】:2020-05-31 19:22:59
【问题描述】:

我在 Spring Boot 中的资源类路径位置中有多个 yml 文件,例如 Spring Boot 的以下结构。最初我只为 application-abc.yml 编写,当时这个文件的所有值都加载到它们相应的类中,但是当我添加到另一个文件 application-xyz.yml 时,它也会加载到它们相应的配置类中,但是此时只在两个配置类中加载 application-xyz.yml 的值。因此,需要帮助在单个构建中配置相应配置文件中的两个文件的值:

-src
  -main
     -java
        -packages
          -config
             -ApplicationAbcConfig.java
             -ApplicationConfig.java
             -ApplicationFactory.java
             -ApplicationXyzConfig.java
             -Authentication.java
             -Operations.java
             -Payload.java
             -RequestPayload.java
             -ResponsePayload.java

         -services
             -YmlConfigurationSelection.java

         -resources
            -application.yml
            -application-abc.yml
            -application-xyz.yml

         -MultipleYmlDemoProject.java

application-abc.yml 的内容

authentication:
  name: name
  type: type
  payload:
    request:
      - sequence: 1
        attributes:
          - attributes1
          - attributes2
    response:
      - sequence: 1
        attributes:
          - attributes3
          - attributes4

operations:
  name: name
  type: type
  payload:
    request:
      - sequence: 1
        attributes:
          - attributes5
          - attributes6
    response:
      - sequence: 1
        attributes:
          - attributes7
          - attributes8

application-xyz.yml 的内容

authentication:
  name: name
  type: type
  payload:
    request:
      - sequence: 1
        attributes:
          - attributes9
          - attributes10
    response:
      - sequence: 1
        attributes:
          - attributes11
          - attributes12

operations:
  name: name
  type: type
  payload:
    request:
      - sequence: 1
        attributes:
          - attributes13
          - attributes14
    response:
      - sequence: 1
        attributes:
          - attributes15
          - attributes16

ApplicationConfig.java 的内容

public interface ApplicationConfig {
    public Authentication getAuthentication();

    public void setAuthentication(Authentication authentication);

    public Operations getOperations();

    public void setOperations(Operations operations);
}

Authentication.java 的内容

public class Authentication {
    private String name;
    private String type;
    private Payload payload;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Payload getPayload() {
        return payload;
    }

    public void setPayload(Payload payload) {
        this.payload = payload;
    }
}

Operations.java 的内容

public class Operations {
    private String name;
    private String type;
    private Payload payload;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Payload getPayload() {
        return payload;
    }

    public void setPayload(Payload payload) {
        this.payload = payload;
    }
}

Payload.java 的内容

public class Payload {
    private List<RequestPayload> request;
    private List<ResponsePayload> response;

    public List<RequestPayload> getRequest() {
        return request;
    }

    public void setRequest(List<RequestPayload> request) {
        this.request = request;
    }

    public List<ResponsePayload> getResponse() {
        return response;
    }

    public void setResponse(List<ResponsePayload> response) {
        this.response = response;
    }
}

RequestPayload.java 的内容

public class RequestPayload {
    private String sequece;
    private List<String> attributes;

    public String getSequece() {
        return sequece;
    }

    public void setSequece(String sequece) {
        this.sequece = sequece;
    }

    public List<String> getAttributes() {
        return attributes;
    }

    public void setAttributes(List<String> attributes) {
        this.attributes = attributes;
    }
}

ResponsePayload.java 的内容

public class ResponsePayload {
    private String sequece;
    private List<String> attributes;

    public String getSequece() {
        return sequece;
    }

    public void setSequece(String sequece) {
        this.sequece = sequece;
    }

    public List<String> getAttributes() {
        return attributes;
    }

    public void setAttributes(List<String> attributes) {
        this.attributes = attributes;
    }
}

ApplicationAbcConfig.java 的内容

@Configuration
@SpringBootConfiguration
@EnableConfigurationProperties
@org.springframework.context.annotation.PropertySource("classpath:application-abc.yml")
public class ApplicationAbcConfig implements ApplicationConfig, PropertySourceFactory {
    private Authentication authentication;
    private Operations operations;

    @Override
    public Authentication getAuthentication() {
        return authentication;
    }

    @Override
    public void setAuthentication(Authentication authentication) {
        this.authentication = authentication;
    }

    @Override
    public Operations getOperations() {
        return operations;
    }

    @Override
    public void setOperations(Operations operations) {
        this.operations = operations;
    }

    @Override
    public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
        Properties propertiesFromYaml = loadYamlIntoProperties(resource);
        String sourceName = name != null ? name : resource.getResource().getFilename();
        return new PropertiesPropertySource(sourceName, propertiesFromYaml);
    }

    private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
        try {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();
            return factory.getObject();
        } catch (IllegalStateException e) {
            // for ignoreResourceNotFound
            Throwable cause = e.getCause();
            if (cause instanceof FileNotFoundException)
                throw (FileNotFoundException) e.getCause();
            throw e;
        }
    }
}

ApplicationXyzConfig.java 的内容

@Configuration
@SpringBootConfiguration
@EnableConfigurationProperties
@org.springframework.context.annotation.PropertySource("classpath:application-xyz.yml")
public class ApplicationXyzConfig implements ApplicationConfig, PropertySourceFactory {
    private Authentication authentication;
    private Operations operations;

    @Override
    public Authentication getAuthentication() {
        return authentication;
    }

    @Override
    public void setAuthentication(Authentication authentication) {
        this.authentication = authentication;
    }

    @Override
    public Operations getOperations() {
        return operations;
    }

    @Override
    public void setOperations(Operations operations) {
        this.operations = operations;
    }

    @Override
    public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
        Properties propertiesFromYaml = loadYamlIntoProperties(resource);
        String sourceName = name != null ? name : resource.getResource().getFilename();
        return new PropertiesPropertySource(sourceName, propertiesFromYaml);
    }

    private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
        try {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();
            return factory.getObject();
        } catch (IllegalStateException e) {
            // for ignoreResourceNotFound
            Throwable cause = e.getCause();
            if (cause instanceof FileNotFoundException)
                throw (FileNotFoundException) e.getCause();
            throw e;
        }
    }
}

ApplicationFactory.java 的内容

@Component
public class ApplicationFactory {
    @Autowired
    private ApplicationAbcConfig applicationAbcConfig;

    @Autowired
    private ApplicationXyzConfig applicationXyzConfig;

    public ApplicationConfig getApplicationPropertiesConfig(String application) {
        if (application.equalsIgnoreCase("abc")) {
            return applicationAbcConfig;
        } else if (application.equalsIgnoreCase("xyz")) {
            return applicationXyzConfig;
        } else {
            return null;
        }
    }
}

YmlConfigurationSelection.java 的内容

public class YmlConfigurationSelection {

    @Autowired
    private ApplicationFactory applicationFactory;

    private ApplicationConfig applicationConfig;

    public Object accessingProperties(String application) {
        applicationConfig = applicationFactory.getApplicationPropertiesConfig(application);

        return null;
    }
}

MultipleYmlDemoProject.java 的内容

@SpringBootApplication
@SpringBootConfiguration
@PropertySource(factory = ApplicationAbcConfig.class, value = "classpath:application-abc.yml")
@PropertySource(factory = ApplicationXyzConfig.class, value = "classpath:application-xyz.yml")
public class MultipleYmlDemoProject {

    public class MultipleYmlDemo {

        public static void main(String[] args) {
            ConfigurableApplicationContext ctx =
                    SpringApplication.run(YamlPropertysourceApplication.class, args);
            ConfigurableEnvironment env = ctx.getEnvironment();
        }
    }

}

【问题讨论】:

    标签: java spring-boot yaml configuration-files properties-file


    【解决方案1】:

    您似乎有一个旧的 Spring 应用程序试图迁移到 Spring Boot。

    Spring boot 原生使用 yaml 文件,因此如果您以 Spring Boot 方式进行集成,则可以删除许多您必须维护的样板代码。配置的命名也有问题:名称application-&lt;something&gt;.yml 保留用于spring boot 配置文件,也许如果你将重命名为myprops-abc/xyz.yaml 它会以不同的方式运行,我不能肯定地说。

    总而言之,我建议您采用以下方式,这比 IMO 更好:

    1. 必须将两个配置集加载到一个配置中,因此请创建一个表示该配置的配置属性文件:
    
    @ConfigurationProperties(prexix="security")
    public class SecurityConfigProperties {
    
        private SecurityRealm abc;
        private SecurityRealm xyz;
    
        // getters, setters
    }
    
    public class SecurityRealm {
        private Authentication autentication;
        private Operations operations;
        // getters setters 
    }
    
    public class Authentication {...}
    private class Operations {...}
    
    1. 现在将 abc 和 xyz yaml 中的所有内容放入一个文件 application.yaml 并给出“安全”前缀:
    
    security:
       abc:   // note, this 'abc' matches the field name of the configuration
         authentication: 
            ...
         operations:
            ....
       xyz:
         authentication: 
            ...
         operations:
            ....
    
    1. 好的,一切都映射好了,像这样创建配置:
    @Configuration
    @EnableConfigurationProperties(SecurityConfigProperties.class)
    public class SecurityConfiguration {
    
        @Bean
        public SecurityBeanForABC(SecurityConfigProperties config) {
          return new SecurityBeanForABC(config.getAbc().getAuthentication(), config.getAbc().getOperations());
        } 
    
        ... the same for XYZ
    }
    
    

    请注意,使用这种方法,您只需在 java 对象中维护配置映射,并且没有用于加载/解析属性的代码) - 一切都由 spring boot 自动完成。如果您配置一个特殊的注释处理器并拥有一个下降 IDE,您甚至可以获得这些 yaml 属性的自动完成功能,但它超出了这个问题的范围。关键是用spring boot直接支持的方式做事有很多优点:)

    【讨论】:

    • 实际上,我不能将所有内容都写在像 application.yml 这样的单个 yml 文件中,因为我有这样的情况,不同的应用程序需要许多不同的配置,这会导致单个 yml 文件过载。所以,如果你能帮助处理不同的文件,那对我会有帮助。为此,我将非常感谢您。
    • 当然可以。像以前一样创建不同的文件:application-abc.yml、application-xyz.yml。一个将包含:security:abc:...,另一个将包含 security:xyz:...(关键是它们仍然会有不同的前缀)。现在使用 --spring.profiles.active=xyz,abc 运行应用程序,它将加载这两个文件。配置将“合并”到 SecurityConfigProperties
    • 嗨,我想知道一些关于这个问题的延伸。作为@Mark Bramnik 在我的情况下工作正常的答案,但我想要一些改变,比如我想从应用程序含义之外读取属性'application-abc.yml'和'application-xyz.yml'文件,即使在部署jar文件之后也是如此。所以,如果有人可以帮助我,那我很高兴。
    • 为什么需要这个?一般来说,在 Spring Boot 中,您可以指定一个包含配置的文件夹(它不必在 jar 中),但它仍会在应用程序启动期间读取所有配置。但是,您可以将使用此配置的 Bean 定义为 @Lazy,以便仅在有人调用它们时才实际初始化它们,而不是在启动期间直接初始化。
    • 我需要它,因为其他人会编写属性,而我只需要读取所有这些属性。那么,你能用一些小例子来解释一下吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-28
    • 2018-10-29
    • 2015-04-19
    • 1970-01-01
    • 1970-01-01
    • 2015-05-08
    相关资源
    最近更新 更多