简体   繁体   English

Spring Boot具有相同名称和相同属性名称的多个配置文件

[英]Spring Boot multiple configurations files with same names and same properties names

I am trying to setup a Spring Boot monolithic app which should behave like a microservice and I have some issues to manage configurations (.properties). 我正在尝试设置一个Spring Boot单片应用程序,它应该像微服务一样,我有一些问题来管理配置(.properties)。 This is how I organized the project ( resources folder) : 这是我组织项目( resources文件夹)的方式: 资源目录树

As you can see there are common properties files : application.properties , application-dev.properties and application-prod.properties these properties should be shared by all sub-properties and they can eventually be overridden. 如您所见,有一些常见的属性文件: application.propertiesapplication-dev.propertiesapplication-prod.properties这些属性应该由所有子属性共享,并且最终可以覆盖它们。

Each service has its own data source url and it also depending on the active profile : H2 for dev and MySQL for prod . 每个service都有自己的数据源URL,它还取决于活动的配置文件: H2用于devMySQL用于prod

Here an exemple of how I manage configurations : 这是我如何管理配置的例子:

Contents of common application.properties : 常见application.properties内容:

spring.profiles.active=dev
spring.config.additional-location=classpath:productservice/, classpath:userservice/,classpath:financeservice/, classpath:securityservice/ #I am not sure this works...
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.database=default
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none 
spring.jpa.properties.validation-mode=none 

Contents of common application-dev.properties : 常见application-dev.properties内容:

spring.datasource.driver-class-name=org.h2.Driver
spring.h2.console.enabled=true
spring.h2.console.path=/db
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false
spring.datasource.username=sa # We override data source username and paswword
spring.datasource.password=
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect

Contents of common application-prod.properties : 常见application-prod.properties内容:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

Now for specific services : 现在针对特定服务:

productservice : 产品服务:

Content of application.properties : application.properties内容:

spring.liquibase.change-log=classpath:productservice/db/changelog/db.changelog-master.xml
spring.liquibase.default-schema=productservicedb
spring.liquibase.check-change-log-location=true

Content of application-dev.properties : application-dev.properties内容:

spring.datasource.url=jdbc:h2:mem:productservicedb;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS productservicedb;MV_STORE=FALSE;MVCC=FALSE
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect

Content of application-prod.properties : application-prod.properties内容:

spring.datasource.url=jdbc:mysql://localhost:3306/productservicedb?useSSL=false

And for userservice I have : 对于用户服务我有:

Content of application.properties : application.properties内容:

spring.liquibase.change-log=classpath:userservice/db/changelog/db.changelog-master.xml
spring.liquibase.default-schema=userservice
spring.liquibase.check-change-log-location=true

Content of application-dev.properties : application-dev.properties内容:

spring.datasource.url=jdbc:h2:mem:userservicedb;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS userservicedb;MV_STORE=FALSE;MVCC=FALSE
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect

Content of application-prod.properties : application-prod.properties内容:

spring.datasource.url=jdbc:mysql://localhost:3306/userservicedb

And so on ... for other services. 等等...用于其他服务。

To configure each data source I proceed like this : 要配置每个数据源,我按以下步骤操作:

productservice : 产品服务:

1- Retrieve properties from environment : 1-从环境中检索属性:

@Configuration( "productServiceProperties" )
@Getter
@Setter
@PropertySource( value = { "classpath:productservice/application.properties",
  "classpath:productservice/application-${spring.profiles.active}.properties" } )
public class ProductServiceProperties {

   @Autowired//I want `Environment` to contain properties from common properties + files in @PropertySource above
   private Environment environment;

    // ========DATASOURCE PROPERTIES=========
   private String      datasourceDriverClass;
   private String      datasourceUsername;
   private String      dataSourcePassword;
   private String      dataSourceUrl;

   // ========LIQUIBASE PROPERTIES==========
   private String      liquibaseChangeLog;
   private String      liquibaseDefaultSchema;

   @PostConstruct
   public void init() {
      this.datasourceDriverClass = environment.getProperty( "spring.datasource.driver-class-name" );
      datasourceUsername = environment.getProperty( "spring.datasource.username" );
      dataSourcePassword = environment.getProperty( "spring.datasource.password" );
      dataSourceUrl = environment.getProperty( "spring.datasource.url" );

      liquibaseChangeLog = environment.getProperty( "spring.liquibase.change-log" );
      liquibaseDefaultSchema = environment.getProperty( "spring.liquibase.default-schema" );
      log.debug( "Initialisation {} ", datasourceDriverClass );
  }
}

2- Inject them in the DB configuration : 2-在DB配置中注入它们:

@Configuration
@EnableJpaRepositories( basePackages = "com.company.product.repository", entityManagerFactoryRef = "productServiceEntityManager", transactionManagerRef = "productServiceTransactionManager", considerNestedRepositories = true )
@EnableTransactionManagement( proxyTargetClass = false )
public class ProductServiceDBConfig {

    private static final String      packageToScan = "com.company.product.models";

    @Autowired
    private ProductServiceProperties productServiceProperties;

    @Bean( name = "productServiceDataSource" )
    public DataSource productServiceDataSource() {
       DriverManagerDataSource dataSource = new DriverManagerDataSource();
       dataSource.setDriverClassName( productServiceProperties.getDatasourceDriverClass() );
       dataSource.setUrl( productServiceProperties.getDataSourceUrl() );
       dataSource.setUsername( productServiceProperties.getDatasourceUsername() );
       dataSource.setPassword( productServiceProperties.getDataSourcePassword() );
       return dataSource;
    }

   @Bean
public JpaVendorAdapter productServiceVendorAdapter() {
    HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
    hibernateJpaVendorAdapter.setGenerateDdl( false );
    hibernateJpaVendorAdapter.setShowSql( true );
    return hibernateJpaVendorAdapter;
}

@Bean( name = "productServiceEntityManager" )
public LocalContainerEntityManagerFactoryBean productServiceEntityManager() {
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setDataSource( productServiceDataSource() );
    emf.setPackagesToScan( packageToScan );
    emf.setJpaVendorAdapter( productServiceVendorAdapter() );
    return emf;
}

@Bean( name = "productServiceTransactionManager" )
public PlatformTransactionManager productServiceTransactionManager() {
    JpaTransactionManager productTransactionManager = new JpaTransactionManager();
    productTransactionManager.setEntityManagerFactory( productServiceEntityManager().getObject() );
    return productTransactionManager;
}

@Bean
public SpringLiquibase productServiceLiquibase() {
    SpringLiquibase liquibase = new SpringLiquibase();
    liquibase.setDataSource( productServiceDataSource() );
    liquibase.setChangeLog( productServiceProperties.getLiquibaseChangeLog() );
    liquibase.setDefaultSchema( productServiceProperties.getLiquibaseDefaultSchema() );
    return liquibase;
  }
}

userservice : userservice:

1- 1-

@Configuration( "userServiceProperties" )
@Getter
@Setter
@PropertySource( value = { "classpath:userservice/application.properties",
    "classpath:userservice/application-${spring.profiles.active}.properties" } ) //I want properties from properties file source above
public class UserServiceProperties {

    @Autowired //I want `Environment` to contain properties from common properties + files in @PropertySource above
    private Environment environment;

    // ========DATASOURCE PROPERTIES=========
    private String      datasourceDriverClass;
    private String      datasourceUsername;
    private String      dataSourcePassword;
    private String      dataSourceUrl;

    // ========LIQUIBASE PROPERTIES==========
    private String      liquibaseChangeLog;
    private String      liquibaseDefaultSchema;

    @PostConstruct
    public void init() {
        datasourceDriverClass = environment.getProperty( "spring.datasource.driver-class-name" );
        datasourceUsername = environment.getProperty( "spring.datasource.username" );
        dataSourcePassword = environment.getProperty( "spring.datasource.password" );
        dataSourceUrl = environment.getProperty( "spring.datasource.url" );

        liquibaseChangeLog = environment.getProperty( "spring.liquibase.change-log" );
        liquibaseDefaultSchema = environment.getProperty( "spring.liquibase.default-schema" );
    }
}

2- 2-

@Configuration
@EnableJpaRepositories( basePackages = "com.company.user.repository", entityManagerFactoryRef = "userServiceEntityManager", transactionManagerRef = "userServiceTransactionManager", considerNestedRepositories = true )
@EnableTransactionManagement( proxyTargetClass = false )
public class UserServiceDBConfig {

private static final String         packageToScan = "com.company.user.models";

   @Autowired
   private UserServiceProperties userServiceProperties;

   @Bean( name = "userServiceDataSource" )
   public DataSource userServiceDataSource() {
      DriverManagerDataSource dataSource = new DriverManagerDataSource();
      dataSource.setDriverClassName( userServiceProperties.getDatasourceDriverClass() );
      dataSource.setUrl( userServiceProperties.getDataSourceUrl() );
      dataSource.setUsername( userServiceProperties.getDatasourceUsername() );
      dataSource.setPassword( userServiceProperties.getDataSourcePassword() );
      return dataSource;
  }

  @Bean
  public JpaVendorAdapter userServiceVendorAdapter() {
      HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
      hibernateJpaVendorAdapter.setGenerateDdl( false );
      hibernateJpaVendorAdapter.setShowSql( true );
      return hibernateJpaVendorAdapter;
  }

  @Bean( name = "userServiceEntityManager" )
  public LocalContainerEntityManagerFactoryBean userServiceEntityManager() {
      LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
      emf.setDataSource( userServiceDataSource() );
      emf.setPackagesToScan( packageToScan );
      emf.setJpaVendorAdapter( userServiceVendorAdapter() );
      return emf;
  }

  @Bean( name = "userServiceTransactionManager" )
  public PlatformTransactionManager userServiceTransactionManager() {
      JpaTransactionManager userTransactionManager = new JpaTransactionManager();
      userTransactionManager.setEntityManagerFactory( userServiceEntityManager().getObject() );
      return userTransactionManager;
  }

  @Bean
  public SpringLiquibase userServiceLiquibase() {
      SpringLiquibase liquibase = new SpringLiquibase();
      liquibase.setDataSource( userServiceDataSource() );
      liquibase.setChangeLog( userServiceProperties.getLiquibaseChangeLog() );
      liquibase.setDefaultSchema( userServiceProperties.getLiquibaseDefaultSchema() );
      return liquibase;
   }
}

The problem is, as I @Autowired Environment to get my properties and all properties have same names, some properties always take precedence over other properties. 问题是,由于@Autowired Environment获取我的属性和所有属性具有相同的名称,因此某些属性始终优先于其他属性。 Eg the property spring.datasource.url contains the same value in both services. 例如,属性spring.datasource.url在两个服务中包含相同的值。

I use Environment and not @Value neither @ConfigurationProperties because it gets properties basing on the active profile and that exactly what I want. 我使用Environment而不是@Value既不是@ConfigurationProperties因为它根据活动的配置文件获取属性,这正是我想要的。

My questions are : 我的问题是:

  • Is it possible to configure Environment to get properties from the configuration class where it is injected? 是否可以配置Environment以从注入它的配置类中获取属性?

  • If not, is there a simple way to achieve what I want to do? 如果没有,有没有一种简单的方法来实现我想做的事情?

  • Should I configure multiple application contexts (one per service) to isolate each Environment variable from other? 我应该配置多个应用程序上下文(每个服务一个)以将每个Environment变量与其他Environment变量隔离吗? (I am not sure this would work) (我不确定这会起作用)

Thanks a lot (and sorry for the length of this post) 非常感谢(对于这篇文章的篇幅感到抱歉)

I solve the problem myself with the suggestion of Andy Wilkinson (@ankinson) on Twitter. 我自己在推特上提出Andy Wilkinson(@ankinson)的建议解决了这个问题。

We can't have many properties files with same name. 我们不能有许多具有相同名称的属性文件。 So I had to rename my sub configurations files like this : 所以我不得不重命名我的子配置文件,如下所示:

product.properties
product-dev.properties
product-prod.properties

And so on... 等等...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring Boot中的MessageSource会允许使用同一语言的多个属性文件吗? - Will MessageSource in Spring Boot allow using multiple properties files for the same language? .properties 文件中的 Spring Boot OAuth2 安全属性名称? - Spring Boot OAuth2 Security properties names in .properties files? 如何在同一个 Tomcat 上部署多个带有外部配置的 Spring Boot 应用程序? - How to deploy multiple Spring boot applications with external configurations on the same Tomcat? Java Files.copy多个文件,不同的名称,相同的内容 - Java Files.copy Multiple Files, Different Names, Same Contents 在Spring中读取具有相同变量名的2个属性文件 - Reading 2 property files having same variable names in Spring 基于请求的同一 Spring Boot 应用程序的多个属性文件 - Multiple property files for same Spring Boot Application based on request swagger 2.0 - 如何解决 spring 引导应用程序中不同包中的相同响应 class 名称问题 - swagger 2.0 - how to solve same response class names in different packages issue in spring boot application 同一场战争的多种配置 - Multiple configurations of the same war 有没有办法在Spring引导中获取所有配置属性的名称? - Is there a way to get the names of all configuration properties in Spring boot? Spring 引导:属性文件中的字段名称和运行时的字段值 - Spring boot : Field names from properties file, and field values at runtime
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM