我有一个spring boot后端,其中有一个主数据库,保存租户数据库的连接字符串,启动应用程序时,我调用主数据库以获取所有租户的连接信息,并将它们放入目标数据源中,每个符号都正常工作,我可以进行多个api调用,响应将根据我正在处理的租户而定,问题是当我向主数据库添加新租户时,我不想重新启动后端,因此我对数据源bean进行了另一个调用,以便它得到刷新,它会被刷新,查找键也会更改,但我从默认数据源而不是刚才添加的数据源获取数据。
我主要是受到这篇文章的启发,下面是我所拥有的一些代码
这是租户代码的contextholder,我将其用作数据源的查找键
public final class TenantContextHolder {
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static final List<String> supportedTenants = new ArrayList<>();
private TenantContextHolder () {
super();
}
public static void setTenantContext(String tenantCode) {
threadLocal.set(tenantCode);
}
public static String getTenantContext() {
return threadLocal.get();
}
}
这是一个简单的拦截器,我用它来检查租户是否已经存在于支持的租户列表中,这样我就可以再次调用datasourcebean,因为它可能刚刚添加到masterdb中
public class DataSourceInterceptor extends HandlerInterceptorAdapter {
private final DBConfig dbConfig;
@Autowired
public DataSourceInterceptor(DBConfig dbConfig) {
this.dbConfig = dbConfig;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (request.getHeader(TENANT_HEADER_NAME) != null) {
try {
String tenantCode= request.getHeader(TENANT_HEADER_NAME);
TenantContextHolder.setTenantContext(tenantCode);
if (TenantContextHolder.supportedTenants.contains(tenantCode)) {
return super.preHandle(request, response, handler);
} else {
log.error("tenant provided {} not supported, trying to refresh dataSource list ...", request.getHeader(TENANT_HEADER_NAME));
dbConfig.dataSource();
if (TenantContextHolder.supportedTenants.contains(tenantCode)) {
return super.preHandle(request, response, handler);
}
log.error("Tenant provided {} is still not supported, can't proceed to datasource",
request.getHeader(TENANT_HEADER_NAME));
throw new HttpCustomException(SOME_CODE);
}
} catch (IllegalArgumentException e) {
log.error("Tenant provided not valid, can't proceed to datasource", e);
throw new HttpCustomException(SOME_CODE);
}
} else {
log.error("No tenant provided, can't proceed to datasource");
throw new HttpCustomException(SOME_CODE); }
}
}
这是我的数据源bean
@Bean()
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public DataSource dataSource() {
TenantContextHolder.supportedTenants.clear();
List<DataSourceInfo> dataSourcesInfo = getTenantDataSourceInfoFromMasterDB();
TenantContextHolder.supportedTenants.addAll(dataSourcesInfo.stream().map(DataSourceInfo::getTenantCode).collect(Collectors.toList()));
CustomRoutingDataSource customDataSource = new CustomRoutingDataSource();
customDataSource.setTargetDataSources(tenantsDataSource);
customDataSource.setDefaultTargetDataSource(tenantsDataSource.get(dataSourcesInfo.get(0).getTenantCode()));//i'm aware of the 0 here it's just the default datasource, for when i don't have a lookup key or when it's not found
return customDataSource;
}
最后,这是保存连接信息的datasourceinfo实体的结构
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class DataSourceInfo {
Integer id;
private String url;
private String username;
private String password;
private String driverClassName;
private String tenantCode;
...
}
正如我所说,每当我重新启动应用程序时,一切都很好,但是当我在主数据库中添加一个新租户,并为此租户进行api调用时,我会得到一个日志,说明它不存在,然后它会再次调用bean,它会将此新租户添加到目标数据源中,但响应总是我设置为默认值的第一个租户,没有缓存,所以肯定不是这样,即使有缓存,每个租户的缓存都是不同的
暂无答案!
目前还没有任何答案,快来回答吧!