我正在尝试设置一个Spring Boot单片应用程序,它应该像微服务一样,我有一些问题需要管理配置(.properties)。
这是我组织项目(resources
文件夹)的方式:
正如您所看到的,有一些常见的属性文件:application.properties
,application-dev.properties
和application-prod.properties
这些属性应该由所有子属性共享,并且最终可以覆盖它们。
每个service
都有自己的数据源网址,并且还取决于有效的个人资料:[{1}}为H2
,dev
为MySQL
。
以下是我如何管理配置的例子:
常见prod
的内容:
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
的内容:
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
的内容:
application-prod.properties
现在针对特定服务:
productservice:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
的内容:
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
的内容:
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
的内容:
application-prod.properties
对于 userservice ,我有:
spring.datasource.url=jdbc:mysql://localhost:3306/productservicedb?useSSL=false
的内容:
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
的内容:
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
的内容:
application-prod.properties
等等......用于其他服务。
要配置每个数据源,我按照以下步骤操作:
productservice:
1-从环境中检索属性:
spring.datasource.url=jdbc:mysql://localhost:3306/userservicedb
2-在数据库配置中注入它们:
@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 );
}
}
userservice:
1-
@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;
}
}
2-
@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" );
}
}
问题是,由于我@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;
}
}
获取我的属性并且所有属性具有相同的名称,因此某些属性始终优先于其他属性。例如。属性@Autowired Environment
在两个服务中包含相同的值。
我使用spring.datasource.url
而不是Environment
@Value
,因为它会根据活动配置文件获取属性,而这正是我想要的。
我的问题是:
是否可以配置@ConfigurationProperties
从注入它的配置类中获取属性?
如果没有,有没有一种简单的方法来实现我想做的事情?
我应该配置多个应用程序上下文(每个服务一个)以将每个Environment
变量与其他变量隔离开来吗? (我不确定这会起作用)
非常感谢(对于这篇文章的篇幅感到抱歉)
答案 0 :(得分:0)
我自己在推特上提出Andy Wilkinson(@ankinson)的建议解决了这个问题。
我们不能拥有许多同名的属性文件。所以我不得不重命名我的子配置文件:
product.properties
product-dev.properties
product-prod.properties
等等......