在多租户 Spring Boot 应用程序中,我尝试加载配置对象。理想情况下,我想以编程方式将某些属性文件加载到配置对象中。我正在寻找一种简单的方法来通过传递属性文件和将其映射到的最终类来加载配置。以下只是我想要实现的目标的一个示例。
配置的目录结构:
config/
- common.properties
all_tenants_config/
- foo_tenant/
- database.properties
- api.properties
- bar_tenant/
- database.properties
- api.properties
配置 POJO:
class DatabaseProperties {
@Value("${database.url}")
private String url;
}
class APIProperties {
@Value("${api.endPoint}")
private String endPoint;
}
配置提供者:
@Singleton
class ConfigurationProvider {
private Map<String, DatabaseProperties> DB_PROPERTIES = new HashMap<>();
private Map<String, APIProperties> API_PROPERTIES = new HashMap<>();
public ConfigurationProvider(@Value(${"tenantsConfigPath"}) String tenantsConfigPath) {
for (File tenant : Path.of(tenantsConfigPath).toFile().listFiles()) {
String tenantName = tenant.getName();
for (File configFile : tenant.listFiles()) {
String configName = configFile.getName();
if ("database.properties".equals(configName)) {
// This is what I'm looking for. An easy way to load the configuration by passing a properties file and the final class to map it to.
DB_PROPERTIES.put(tenant, SPRING_CONFIG_LOADER.load(configFile, DatabaseProperties.class));
} else if ("api.properties".equals(configName)) {
API_PROPERTIES.put(tenant, SPRING_CONFIG_LOADER.load(configFile, API.class));
}
}
}
}
public currentTenantDBProperties() {
return DB_PROPERTIES.get(CURRENT_TENANT_ID);
}
public currentTenantAPIProperties() {
return API_PROPERTIES.get(CURRENT_TENANT_ID);
}
}
简而言之,Spring中有没有一种方法可以将属性文件映射到对象,而不使用默认的Spring配置注释。
好吧,在这种情况下你不需要任何 Spring 的功能。
Spring是一个bean容器,但在这里你只需自己新建一个对象并将其放入你的地图缓存中。
第 1 步:将属性文件解码为 Java Properties 类对象
第2步:将你的属性对象转换为你的目标对象,只需使用一些像objectmapper这样的工具
FileReader reader = new FileReader("db.properties"); // replace file name with your variable
Properties p = new Properties();
p.load(reader);
ObjectMapper mapper = new ObjectMapper();
DatabaseProperties databaseProperties = mapper.convertValue(p,
DatabaseProperties.class);
@ConfigurationProperties
注释可以完成这项工作,允许您加载外部属性。例如来自 applications.properties 文件。
@Configuration
@ConfigurationProperties(prefix = "my.propperties")
public class MyProperties {
// syntax key properties: `[prefix].[fieldName]=value`
private String version, name;
// syntax key properties: `[prefix].[fieldName].[key]=value`
private Map<String, String> map = new LinkedHashMap<>();
public Map<String, String> getMap() { return map; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
前面的 POJO 定义了以下属性:
my.propperties.version
字符串类型my.propperties.name
字符串类型my.propperties.map.[key]
地图类型my.propperties
是 @ConfigurationProperties
注释中定义的前缀。默认情况下,属性是从 applications.properties
文件加载的,但我们可以导入外部属性文件。
在 applications.properties 文件中:
my.propperties.version=1.0.0
my.propperties.name=awesome name
my.propperties.map.key0=A
my.propperties.map.key1=B
my.propperties.map.key2=C
将要与“
spring.config.import
”一起使用的所有属性文件导入到 applications.properties 中。 "spring.config.import=filepath".
文档
spring.config.import=config/common.properties,\
config/all_tenants_config/bar_tenant/api.properties,\
config/all_tenants_config/bar_tenant/database.properties,\
config/all_tenants_config/foo_tenant/api.properties,\
config/all_tenants_config/foo_tenant/database.properties
为 APIProperties 和 DatabaseProperties 创建两个 pojo(用作哈希图中的类型)
class DatabaseProperties {
private String url;
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
}
class APIProperties {
private String endpoint;
public String getEndpoint() { return endpoint; }
public void setEndpoint(String endPoint) {this.endpoint = endPoint; }
}
使用
@ConfigurationProperties
注释和 @Configuration
注释创建类。
@Configuration
注释来指示其作为 Spring 配置类的角色。@ConfigurationProperties
注释,用于启用 applications.properties 文件中的属性绑定。@Configuration
@ConfigurationProperties(prefix = "my.cfg") // => "[prefix].api.[object]=[value]"
class MyConfig {
public static String CURRENT_TENANT_ID = "foo_tenant";
// => [prefix].api.[key | tenant_id].[field name]=value
private final Map<String, APIProperties> api = new LinkedHashMap<>();
// => [prefix].database.[key | tenant_id].[field name]=value
private final Map<String, DatabaseProperties> database = new LinkedHashMap<>();
private String tenant, dev;
public String getDev() { return dev; }
public void setDev(String dev) {this.dev = dev; }
public String getTenant() {
// use tenant id from common.properties
// return tenant;
// or use from static field
return MyConfig.CURRENT_TENANT_ID;
}
public void setTenant(String tenantId) { this.tenant = tenantId; }
public Map<String, APIProperties> getApi() {return api;}
public Map<String, DatabaseProperties> getDatabase() {return database; }
public DatabaseProperties currentTenantDBProperties() {return this.getDatabase().get(this.getTenant());}
public APIProperties currentTenantAPIProperties() {return this.getApi().get(this.getTenant());}
}
前面的 POJO 定义了以下属性:
my.cfg.dev
字符串类型my.cfg.tenant
字符串类型my.cfg.api.[key].[fieldName]
地图my.cfg.database.[key].[fieldName]
地图创建不同的属性文件:
# file: config/common.properties
my.cfg.tenant=bar_tenant
my.cfg.dev=true
# file: config/all_tenants_config/bar_tenant/api.properties
my.cfg.api.[bar_tenant].endpoint=https://localhost/api/v1
# file: config/all_tenants_config/bar_tenant/database.properties
my.cfg.database.[bar_tenant].url="localhost"
# file: config/all_tenants_config/foo_tenant/api.properties
my.cfg.api.[foo_tenant].endpoint=https://api.url.com/api/v1
# file: config/all_tenants_config/foo_tenant/database.properties
my.cfg.database.[foo_tenant].url="https://database.url.com"
注意:您需要将密钥用 [] 括起来以保留其原始值或任何非字母数字、 - 或 的字符。被删除。绑定图。请参阅:doc绑定图
更多信息:外部化配置