目录
2.配置文件 META-INF/spring.factories
一、多租户是什么?
• 多租户技术是一种软件架构技术,是实现如何在多用户(一般是面向企业用户)的环境下共用相同的系统或程序组件,并且可确保各用户间数据的隔离性。
• 多租户技术可以实现多个租户之间共享系统实例,同时又可以实现租户的系统实例的个性化定制。
• 通过在多个租户之间的资源复用,有效节省开发应用的成本。在租户之间共享应用程序的单个实例,可以实现当应用程序升级时,所有租户可以同时升级。
二、多租户数据隔离方案
• 独立数据库
• 共享数据库,隔离数据架构
• 共享数据库,共享数据架构
采用方案:共享数据库,共享数据架构(租户ID隔离)
三、实现步骤
1.引入库
<!--mybatis--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <!--数据库--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--dynamic-datasource--> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> </dependency>
2.配置文件 META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.ronshi.common.tenant.config.TenantConfiguration
3.TenantConfiguration
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore({MybatisAutoConfiguration.class})
@EnableConfigurationProperties({TenantProperties.class})
public class TenantConfiguration {
@Bean
@ConditionalOnMissingBean({TenantLineHandler.class})
public TenantLineHandler tenantHandler(TenantProperties tenantProperties) {
return new TenantHandler(tenantProperties);
}
@Bean
@ConditionalOnMissingBean({TenantLineInnerInterceptor.class})
public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantLineHandler tenantHandler, TenantProperties tenantProperties) {
TenantInterceptor tenantInterceptor = new TenantInterceptor();
tenantInterceptor.setTenantLineHandler(tenantHandler);
tenantInterceptor.setTenantProperties(tenantProperties);
return tenantInterceptor;
}
}
4.TenantProperties
@Data
@ConfigurationProperties(prefix = "ronshi.tenant")
public class TenantProperties {
private Boolean enhance;
private String column;
private List<String> excludeTables;
private List<String> matchUrls;
private List<String> excludeUrls;
public TenantProperties() {
this.enhance = Boolean.FALSE;
this.column = "tenant_id";
this.excludeTables = new ArrayList<>();
this.matchUrls = new ArrayList<>();
matchUrls.add("/**");
this.excludeUrls = new ArrayList<>();
}
}
5.TenantHandler
public class TenantHandler implements TenantLineHandler, SmartInitializingSingleton {
private final TenantProperties tenantProperties;
@Override
public Expression getTenantId() {
Long tenantId = TenantUtil.getTenantId();
if (tenantId == null) {
throw new RuntimeException("请设置租户ID");
}
return new LongValue(tenantId);
}
@Override
public String getTenantIdColumn() {
return this.tenantProperties.getColumn();
}
@Override
public boolean ignoreTable(String tableName) {
return this.tenantProperties.getExcludeTables().contains(tableName);
}
@Override
public void afterSingletonsInstantiated() {
// 实例化后执行
}
public TenantHandler(final TenantProperties tenantProperties) {
this.tenantProperties = tenantProperties;
}
}
6.TenantInterceptor
@Data
public class TenantInterceptor extends TenantLineInnerInterceptor {
private TenantProperties tenantProperties;
}
7.MybatisPlusProperties
@ConfigurationProperties(prefix = "ronshi.mybatis-plus")
@Data
public class MybatisPlusProperties {
private Boolean tenantMode = false;
}
8.MybatisAutoConfiguration
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({MybatisPlusProperties.class})
public class MybatisAutoConfiguration {
@Bean
@ConditionalOnMissingBean({TenantLineHandler.class})
public TenantLineHandler tenantLineHandler() {
return new TenantLineHandler() {
@Override
public Expression getTenantId() {
return new LongValue(0L);
}
@Override
public boolean ignoreTable(String tableName) {
return true;
}
};
}
@Bean
@ConditionalOnMissingBean({TenantLineInnerInterceptor.class})
public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantLineHandler tenantHandler) {
return new TenantLineInnerInterceptor(tenantHandler);
}
/**
* 插件主体
*
* @return MybatisPlusInterceptor
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(TenantLineInnerInterceptor tenantLineInnerInterceptor, MybatisPlusProperties mybatisPlusProperties) {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//判断是否为租户模式
if (Boolean.TRUE.equals(mybatisPlusProperties.getTenantMode())) {
interceptor.addInnerInterceptor(tenantLineInnerInterceptor);
}
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
9.引用租户模块
<!--多租户数据隔离 模块-->
<dependency>
<groupId>com.ronshi</groupId>
<artifactId>tenant-starter</artifactId>
</dependency>
ronshi:
mybatis-plus:
tenant-mode: true
tenant:
exclude-tables:
- tenant
总结
租户模块分包,可根据服务是否为多租户模式,来选择是否加载租户模块。租户字段名称和拦截的表名动态配置。采用了配置属性类、配置类、拦截类、处理类分离的模式,可以灵活扩展。