spring boot-如何做多租户
·
在 Spring Boot 中实现多租户(Multi-Tenancy)通常涉及到在一个应用实例中支持多个租户(例如不同的公司或用户组),每个租户可能有自己的数据隔离和配置。Spring Boot 和 Spring Data 提供了多种方式来实现多租户。以下是几种常见的方法以及如何实现它们的详细步骤:
数据源多租户
1.1 基于 `AbstractRoutingDataSource` 的多租户
`AbstractRoutingDataSource` 是 Spring 提供的一个抽象类,可以动态地决定哪个数据源用于当前的线程。你可以通过在数据源中使用 `AbstractRoutingDataSource` 来实现多租户支持。这里的核心思想是根据当前的租户标识动态选择数据源。
步骤:
1. 定义租户上下文
你需要一个上下文来保存当前租户的信息,通常使用 `ThreadLocal` 实现。
public class TenantContext {
private static final ThreadLocal<String> currentTenant = new ThreadLocal<>();
public static void setTenantId(String tenantId) {
currentTenant.set(tenantId);
}
public static String getTenantId() {
return currentTenant.get();
}
public static void clear() {
currentTenant.remove();
}
}
2. 创建动态数据源
扩展 `AbstractRoutingDataSource` 类,动态选择数据源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class TenantRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return TenantContext.getTenantId();
}
}
3. 配置数据源
在 Spring Boot 配置中定义多个数据源,并配置 `TenantRoutingDataSource`。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
TenantRoutingDataSource routingDataSource = new TenantRoutingDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("tenant1", tenant1DataSource());
targetDataSources.put("tenant2", tenant2DataSource());
routingDataSource.setTargetDataSources(targetDataSources);
routingDataSource.setDefaultTargetDataSource(tenant1DataSource());
return routingDataSource;
}
@Bean
public DataSource tenant1DataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/tenant1db");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
@Bean
public DataSource tenant2DataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/tenant2db");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
}
4. 设置租户 ID
在每个请求中,你需要设置当前的租户 ID。这通常可以通过拦截器或过滤器来实现。
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class TenantFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String tenantId = httpRequest.getHeader("X-TenantID");
TenantContext.setTenantId(tenantId);
try {
chain.doFilter(request, response);
} finally {
TenantContext.clear();
}
}
@Override
public void init(FilterConfig filterConfig) {}
@Override
public void destroy() {}
}
更多推荐
所有评论(0)