[英]Spring boot jpa multitenancy with dynamic datasources
我正在嘗試創建一個多租戶 Web 應用程序,並在這里找到了一個很好的教程。 這向我解釋了如何配置 MVC 以查找新租戶(使用CurrentTenantIdentifierResolver
和擴展HandlerInterceptorAdapter
的 MultiTenancyInterceptor ),如何為三個不同的租戶配置三個不同的數據源,以及如何通過擴展AbstractDataSourceBasedMultiTenantConnectionProviderImpl
在運行時為服務器提供正確的數據源
現在,這是一個很好的起點,讓我了解 spring 和 hibernate 中的多租戶是如何工作的,但我想進一步推動這一點,我想讓租戶完全動態,即我不假設一個應用程序可以有多少租戶。
這就是我的想法:
之后,基本的多租戶結構已經在上述鏈接中描述:每次最終用戶向瀏覽器發出請求時,服務器都會詳細說明租戶並返回正確的數據源以查找要使用的數據庫。
任何人都可以向我指出一些資源,如果這是以前做過的(我搜索了很多但沒有讓我開始),或者就使用哪些彈簧類/配置來實現這一點提供一些建議?
提前致謝
如果有人有這種需要,這就是我最終要做的。 任何對此的進一步擴展,或對最佳實踐侵權的評論都將受到歡迎。
擴展AbstractDataSourceBasedMultiTenantConnectionProviderImpl
的DataSourceProvider
必須覆蓋兩個方法
selectAnyDataSource
返回一個@Autowired DataSource
,該@Autowired DataSource
selectAnyDataSource
Spring 使用為應用程序實例化數據源的常用方法進行實例化。selectDataSource(String tenant)
執行以下操作:
DataSourceProperties
DataSourceBuilder
創建並返回一個新的DataSourceBuilder
,使用先前實例化的 DataSourceProperties 中的字段作為屬性(很有用,因為 Spring 從數據庫 URL 動態地為您提供驅動程序類名稱)此處提供的代碼,請隨意使用:
String configPath = [...]; // Instantiate your configuration path
File file = new File(realPath);
DataSourceProperties dsProp = new DataSourceProperties();
Properties properties = new Properties();
try {
properties.load(new FileInputStream(file));
} catch (IOException e) {
throw new TenantNotConfiguredException(tenant); // Custom exception
}
PropertiesConfigurationFactory<DataSourceProperties> pcf = new PropertiesConfigurationFactory<>(dsProp);
pcf.setTargetName(DataSourceProperties.PREFIX);
pcf.setProperties(properties);
try {
dsProp = pcf.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return DataSourceBuilder.create()
.url(dsProp.getUrl())
.driverClassName(dsProp.getDriverClassName())
.username(dsProp.getUsername())
.password(dsProp.getPassword())
.build();
這是完整的代碼。 我希望它有所幫助,因為我在到達這里之前也遭受了痛苦。
@RestController
@RequestMapping(value = "/accounts", headers = "Accept=application/json")
public class AppController {
@Autowired
UserService service;
@Autowired
AppService appService;
////////working on dynamic loading of datasource
@Autowired
Map<String, DataSource> dataSourcesMtApp;
public void updateDataSource(String url, String username, String password, String tenant) {
try {
DataSourceBuilder factory1 = DataSourceBuilder.create(MultiTenancyJpaConfiguration.class.getClassLoader()).url(url)
.username(username).password(password)
.driverClassName("com.mysql.jdbc.Driver");
dataSourcesMtApp.put(tenant, factory1.build());
System.out.println("Size:......................................................" + dataSourcesMtApp.size());
} catch (Exception ex) {
Logger.getLogger(AppController.class.getName()).log(Level.SEVERE, null, ex);
}
}
@PostMapping("/create-account")
public Response createAccount(@RequestBody ConnectionParams request) {
String tenant = ConnectionUtils.initializeDatabase(request.getDatabase(), request.getDbusername(), request.getDbpassword());
updateDataSource("jdbc:mysql://localhost:3306/" + request.getDatabase() + "?useSSL=false", request.getDbusername(), request.getDbpassword(), tenant);
TenantContextHolder.setTenantId(tenant);
Users user = new Users();
user.setPassword(request.getLoginpassword());
user.setUsername(request.getLoginusername());
user.setTenant(tenant);
user = service.save(user);
String response = "Account Setup Completed TenantId: " + tenant + " Username: " + user.getUsername();
Response rp = new Response();
rp.setResult(response);
return rp;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.