当前位置:网站首页>quarkus+saas多租户动态数据源切换实现简单完美
quarkus+saas多租户动态数据源切换实现简单完美
2022-06-23 11:03:00 【InfoQ】

package com.weir.quarku.tanent;
import io.quarkus.arc.Unremovable;
import io.quarkus.hibernate.orm.runtime.tenant.TenantResolver;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import java.util.Optional;
/**
* 识别动态租户信息(一般通过web的request从header传递租户信息)
* @author weir
*
*/
@RequestScoped
@Unremovable
public class InjectableTenantResolver implements TenantResolver {
@Inject
TenantConnections tenantConnections;
private Optional<String> requestTenant = Optional.empty();
public void setRequestTenant(String requestTenant) {
this.requestTenant = Optional.of(requestTenant);
}
/**
* 默认租户
*/
@Override
public String getDefaultTenantId() {
return tenantConnections.allTenants()
.stream()
.findAny()
.orElseThrow(() -> new RuntimeException("No tenants known at all"));
}
/**
* 当前租户
*/
@Override
public String resolveTenantId() {
return requestTenant.orElseThrow(() -> new RuntimeException("No tenant specified by current request"));
}
}
package com.weir.quarku.tanent;
import io.agroal.api.AgroalDataSource;
import io.agroal.api.configuration.AgroalDataSourceConfiguration;
import io.agroal.api.configuration.supplier.AgroalDataSourceConfigurationSupplier;
import io.agroal.api.security.NamePrincipal;
import io.agroal.api.security.SimplePassword;
import io.quarkus.arc.Unremovable;
import io.quarkus.hibernate.orm.runtime.customized.QuarkusConnectionProvider;
import io.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import static io.agroal.api.configuration.AgroalConnectionPoolConfiguration.ConnectionValidator.defaultValidator;
import static java.time.Duration.ofSeconds;
/**
* 动态产生并切换数据源连接
* @author weir
*
*/
//@PersistenceUnitExtension
@ApplicationScoped
@Unremovable
public class TenantConnections implements TenantConnectionResolver {
private final Map<String, DBConnectionInfo> dbConnectionInfoMap = new HashMap<>();
// {
// {
// put("weir",new DBConnectionInfo("localhost", 3306, "root", "336393", "quarkus-demo"));
// put("weir-blog",new DBConnectionInfo("localhost", 3306, "root", "336393", "weirblog"));
// }
// };
private final Map<String, ConnectionProvider> cache = new HashMap<>();
private static AgroalDataSourceConfiguration createDataSourceConfiguration(DBConnectionInfo dbConnectionInfo) {
System.out.println("------------------createDataSourceConfiguration--------------" + dbConnectionInfo);
return new AgroalDataSourceConfigurationSupplier()
.dataSourceImplementation(AgroalDataSourceConfiguration.DataSourceImplementation.AGROAL)
.metricsEnabled(false)
.connectionPoolConfiguration(cp -> cp.minSize(0).maxSize(5).initialSize(0)
.connectionValidator(defaultValidator()).acquisitionTimeout(ofSeconds(5))
.leakTimeout(ofSeconds(5)).validationTimeout(ofSeconds(50)).reapTimeout(ofSeconds(500))
.connectionFactoryConfiguration(cf -> cf
.jdbcUrl("jdbc:mysql://" + dbConnectionInfo.getHost() + ":" + dbConnectionInfo.getPort()
+ "/" + dbConnectionInfo.getDb())
.connectionProviderClassName("com.mysql.cj.jdbc.Driver")
// .connectionProviderClassName("org.postgresql.Driver")
.principal(new NamePrincipal(dbConnectionInfo.getUser()))
.credential(new SimplePassword(dbConnectionInfo.getPassword()))))
.get();
}
public Set<String> allTenants() {
getTenant();
System.out.println("---------------TenantConnections--------allTenants-------" + dbConnectionInfoMap.keySet());
return dbConnectionInfoMap.keySet();
}
@Inject
AgroalDataSource defaultDataSource;
private void getTenant() {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = defaultDataSource.getConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery("select * from SysTenant");
while (resultSet.next()) {
dbConnectionInfoMap.put(resultSet.getString("code"),
new DBConnectionInfo(resultSet.getString("host"), resultSet.getInt("port"),
resultSet.getString("username"), resultSet.getString("password"),
resultSet.getString("dbName")));
// System.out.println("--------------------------"+resultSet.getString("name")+"--"+resultSet.getString("username"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public ConnectionProvider resolve(String tenant) {
System.out.println("---------------TenantConnections--------resolve-------" + tenant);
if (!dbConnectionInfoMap.containsKey(tenant)) {
throw new IllegalStateException("Unknown tenantId: " + tenant);
}
if (!cache.containsKey(tenant)) {
try {
DBConnectionInfo dbConnectionInfo = dbConnectionInfoMap.get(tenant);
AgroalDataSource agroalDataSource = AgroalDataSource
.from(createDataSourceConfiguration(dbConnectionInfo));
QuarkusConnectionProvider quarkusConnectionProvider = new QuarkusConnectionProvider(agroalDataSource);
cache.put(tenant, quarkusConnectionProvider);
return quarkusConnectionProvider;
} catch (SQLException ex) {
throw new IllegalStateException("Failed to create a new data source based on the tenantId: " + tenant,
ex);
}
}
return cache.get(tenant);
}
}
package com.weir.quarku.tanent;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
/**
* 拦截web中header的租户信息并设置给TenantResolver(InjectableTenantResolver)
* @author weir
*
*/
@Provider
@ApplicationScoped
public class TenantRequestFilter implements ContainerRequestFilter {
@Inject
InjectableTenantResolver tenantResolver;
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
String tenantId = containerRequestContext.getHeaderString("X-tenant");
if (tenantId != null) {
tenantResolver.setRequestTenant(tenantId);
}
}
}
边栏推荐
- 详解判断大小端的方法
- flutter系列之:flutter中的Wrap
- Stockage d'images - référence
- MAUI使用Masa blazor组件库
- Not satisfied with the effect of the smart park? Please accept this secret script of thingjs
- Economic common sense
- Noi OJ 1.3 20: power C language for computing 2
- The simplest DIY serial port Bluetooth hardware implementation scheme
- Noi OJ 1.4 04: odd even ASCII value judgment C language
- Noi OJ 1.4 03: odd even judging C language
猜你喜欢

STM32F103ZET6单片机双串口互发程序设计与实现

圖片存儲--引用

社招腾讯高P(高级产品经理)的面试手册

"Internet +" contest topic hot docking | I figure to understand 38 propositions of Baidu

Installation and use of binabsinspector, an open source binary file static vulnerability analysis tool

安卓安全/逆向面试题

最简单DIY基于C#和51单片机上下位机一体化的PCA9685舵机控制程序

【黄金分割点】与【斐波那契数列】

R and rstudio download and install detailed steps

Explain in detail the method of judging the size end
随机推荐
ESP32-CAM高性价比温湿度监控系统
Maui uses Masa blazor component library
How to write a literature review? What should I do if I don't have a clue?
Weidongshan equipment information query routine learning
Design and implementation of distribution network and Internet connection scheme for esp32-cam high cost performance temperature and humidity monitoring system
Simplest DIY remote control computer system based on STM32 ① (capacitive touch + key control)
Unity technical manual - limit velocity over lifetime sub module and inherit velocity sub module
ESP32-CAM高性价比温湿度监控系统配网与上网方案设计与实现
Description of directory files of TLBB series of Tianlong Babu - netbill server [ultra detailed]
JVM easy start-02
Explain in detail the method of judging the size end
torch权重转mindspore
argmax函数笔记-全是细节
list的介绍及使用
DevEco Device Tool 助力OpenHarmony设备开发
Is it difficult to register stocks and open accounts online? Is it safe to open an account online now?
DevEco Device Tool 助力OpenHarmony設備開發
Flutter series: wrap in flutter
1154. day of the year
A child process is created in the program, and then the parent and child processes run independently. The parent process reads lowercase letters on the standard input device and writes them to the pip