mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-31 10:57:15 +08:00 
			
		
		
		
	feat(extension/tenant): 新增 TenantUtils 替换 TenantHandler 接口及其实现类 DefaultTenantHandler
This commit is contained in:
		| @@ -57,4 +57,9 @@ public interface TenantDataSourceHandler { | |||||||
|      * @param dataSourceName 数据源名称 |      * @param dataSourceName 数据源名称 | ||||||
|      */ |      */ | ||||||
|     void removeDataSource(String dataSourceName); |     void removeDataSource(String dataSourceName); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 轮询数据源 | ||||||
|  |      */ | ||||||
|  |     void poll(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -14,21 +14,22 @@ | |||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package top.continew.starter.extension.tenant; | package top.continew.starter.extension.tenant.annotation; | ||||||
|  | 
 | ||||||
|  | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||||||
|  | import top.continew.starter.core.constant.PropertiesConstants; | ||||||
|  | 
 | ||||||
|  | import java.lang.annotation.*; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * 租户处理器 |  * 是否启用租户判断注解 | ||||||
|  * |  * | ||||||
|  * @author 小熊 |  * @author Charles7c | ||||||
|  * @since 2.8.0 |  * @since 2.13.1 | ||||||
|  */ |  */ | ||||||
| public interface TenantHandler { | @Retention(RetentionPolicy.RUNTIME) | ||||||
| 
 | @Target({ElementType.TYPE, ElementType.METHOD}) | ||||||
|     /** | @Documented | ||||||
|      * 在指定租户中执行 | @ConditionalOnProperty(prefix = PropertiesConstants.TENANT, name = PropertiesConstants.ENABLED, havingValue = "true", matchIfMissing = true) | ||||||
|      * | public @interface ConditionalOnEnabledTenant { | ||||||
|      * @param tenantId 租户 ID |  | ||||||
|      * @param runnable 方法 |  | ||||||
|      */ |  | ||||||
|     void execute(Long tenantId, Runnable runnable); |  | ||||||
| } | } | ||||||
| @@ -23,6 +23,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | |||||||
| import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||||||
| import top.continew.starter.core.constant.PropertiesConstants; | import top.continew.starter.core.constant.PropertiesConstants; | ||||||
| import top.continew.starter.extension.tenant.config.TenantProvider; | import top.continew.starter.extension.tenant.config.TenantProvider; | ||||||
|  | import top.continew.starter.extension.tenant.interceptor.TenantInterceptor; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 租户 Web MVC 自动配置 |  * 租户 Web MVC 自动配置 | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ package top.continew.starter.extension.tenant.context; | |||||||
|  |  | ||||||
| import cn.hutool.extra.spring.SpringUtil; | import cn.hutool.extra.spring.SpringUtil; | ||||||
| import com.alibaba.ttl.TransmittableThreadLocal; | import com.alibaba.ttl.TransmittableThreadLocal; | ||||||
|  | import top.continew.starter.core.util.SpringUtils; | ||||||
| import top.continew.starter.extension.tenant.autoconfigure.TenantProperties; | import top.continew.starter.extension.tenant.autoconfigure.TenantProperties; | ||||||
| import top.continew.starter.extension.tenant.config.TenantDataSource; | import top.continew.starter.extension.tenant.config.TenantDataSource; | ||||||
| import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; | import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; | ||||||
| @@ -35,12 +36,12 @@ public class TenantContextHolder { | |||||||
|     /** |     /** | ||||||
|      * 租户上下文 |      * 租户上下文 | ||||||
|      */ |      */ | ||||||
|     private static final TransmittableThreadLocal<TenantContext> CONTEXT = new TransmittableThreadLocal<>(); |     private static final TransmittableThreadLocal<TenantContext> CONTEXT_HOLDER = new TransmittableThreadLocal<>(); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 是否忽略租户 |      * 是否忽略租户 | ||||||
|      */ |      */ | ||||||
|     private static final TransmittableThreadLocal<Boolean> IGNORE = new TransmittableThreadLocal<>(); |     private static final TransmittableThreadLocal<Boolean> IGNORE_HOLDER = new TransmittableThreadLocal<>(); | ||||||
|  |  | ||||||
|     private TenantContextHolder() { |     private TenantContextHolder() { | ||||||
|     } |     } | ||||||
| @@ -51,7 +52,7 @@ public class TenantContextHolder { | |||||||
|      * @param context 上下文 |      * @param context 上下文 | ||||||
|      */ |      */ | ||||||
|     public static void setContext(TenantContext context) { |     public static void setContext(TenantContext context) { | ||||||
|         CONTEXT.set(context); |         CONTEXT_HOLDER.set(context); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -60,7 +61,7 @@ public class TenantContextHolder { | |||||||
|      * @return 上下文 |      * @return 上下文 | ||||||
|      */ |      */ | ||||||
|     public static TenantContext getContext() { |     public static TenantContext getContext() { | ||||||
|         return CONTEXT.get(); |         return CONTEXT_HOLDER.get(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -69,7 +70,7 @@ public class TenantContextHolder { | |||||||
|      * @param ignore 是否忽略租户 |      * @param ignore 是否忽略租户 | ||||||
|      */ |      */ | ||||||
|     public static void setIgnore(boolean ignore) { |     public static void setIgnore(boolean ignore) { | ||||||
|         IGNORE.set(ignore); |         IGNORE_HOLDER.set(ignore); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -78,15 +79,15 @@ public class TenantContextHolder { | |||||||
|      * @return 是否忽略租户 |      * @return 是否忽略租户 | ||||||
|      */ |      */ | ||||||
|     public static boolean isIgnore() { |     public static boolean isIgnore() { | ||||||
|         return Boolean.TRUE.equals(IGNORE.get()); |         return Boolean.TRUE.equals(IGNORE_HOLDER.get()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 清除 |      * 清除 | ||||||
|      */ |      */ | ||||||
|     public static void clearContext() { |     public static void clear() { | ||||||
|         CONTEXT.remove(); |         CONTEXT_HOLDER.remove(); | ||||||
|         IGNORE.remove(); |         IGNORE_HOLDER.remove(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -117,4 +118,23 @@ public class TenantContextHolder { | |||||||
|     public static TenantDataSource getDataSource() { |     public static TenantDataSource getDataSource() { | ||||||
|         return Optional.ofNullable(getContext()).map(TenantContext::getDataSource).orElse(null); |         return Optional.ofNullable(getContext()).map(TenantContext::getDataSource).orElse(null); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 是否启用了租户 | ||||||
|  |      * | ||||||
|  |      * @return 是否启用了租户 | ||||||
|  |      */ | ||||||
|  |     public static boolean isTenantEnabled() { | ||||||
|  |         TenantProperties tenantProperties = SpringUtils.getBean(TenantProperties.class, true); | ||||||
|  |         return tenantProperties != null && tenantProperties.isEnabled(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 是否禁用了租户 | ||||||
|  |      * | ||||||
|  |      * @return 是否禁用了租户 | ||||||
|  |      */ | ||||||
|  |     public static boolean isTenantDisabled() { | ||||||
|  |         return !isTenantEnabled(); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ | |||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package top.continew.starter.extension.tenant.autoconfigure; | package top.continew.starter.extension.tenant.interceptor; | ||||||
| 
 | 
 | ||||||
| import cn.hutool.core.annotation.AnnotationUtil; | import cn.hutool.core.annotation.AnnotationUtil; | ||||||
| import jakarta.servlet.http.HttpServletRequest; | import jakarta.servlet.http.HttpServletRequest; | ||||||
| @@ -23,6 +23,7 @@ import org.springframework.core.Ordered; | |||||||
| import org.springframework.web.method.HandlerMethod; | import org.springframework.web.method.HandlerMethod; | ||||||
| import org.springframework.web.servlet.HandlerInterceptor; | import org.springframework.web.servlet.HandlerInterceptor; | ||||||
| import top.continew.starter.extension.tenant.annotation.TenantIgnore; | import top.continew.starter.extension.tenant.annotation.TenantIgnore; | ||||||
|  | import top.continew.starter.extension.tenant.autoconfigure.TenantProperties; | ||||||
| import top.continew.starter.extension.tenant.config.TenantProvider; | import top.continew.starter.extension.tenant.config.TenantProvider; | ||||||
| import top.continew.starter.extension.tenant.context.TenantContextHolder; | import top.continew.starter.extension.tenant.context.TenantContextHolder; | ||||||
| 
 | 
 | ||||||
| @@ -44,6 +45,7 @@ public class TenantInterceptor implements HandlerInterceptor, Ordered { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { |     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { | ||||||
|  |         // 忽略租户拦截 | ||||||
|         if (handler instanceof HandlerMethod handlerMethod) { |         if (handler instanceof HandlerMethod handlerMethod) { | ||||||
|             TenantIgnore methodAnnotation = handlerMethod.getMethodAnnotation(TenantIgnore.class); |             TenantIgnore methodAnnotation = handlerMethod.getMethodAnnotation(TenantIgnore.class); | ||||||
|             if (methodAnnotation != null) { |             if (methodAnnotation != null) { | ||||||
| @@ -55,11 +57,18 @@ public class TenantInterceptor implements HandlerInterceptor, Ordered { | |||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         // 设置上下文 | ||||||
|         String tenantId = request.getHeader(tenantProperties.getTenantIdHeader()); |         String tenantId = request.getHeader(tenantProperties.getTenantIdHeader()); | ||||||
|         TenantContextHolder.setContext(tenantProvider.getByTenantId(tenantId, true)); |         TenantContextHolder.setContext(tenantProvider.getByTenantId(tenantId, true)); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) { | ||||||
|  |         // 清除上下文 | ||||||
|  |         TenantContextHolder.clear(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public int getOrder() { |     public int getOrder() { | ||||||
|         return Integer.MIN_VALUE; |         return Integer.MIN_VALUE; | ||||||
| @@ -0,0 +1,106 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||||
|  |  * <p> | ||||||
|  |  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * <p> | ||||||
|  |  * http://www.gnu.org/licenses/lgpl.html | ||||||
|  |  * <p> | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package top.continew.starter.extension.tenant.util; | ||||||
|  |  | ||||||
|  | import cn.hutool.extra.spring.SpringUtil; | ||||||
|  | import top.continew.starter.extension.tenant.TenantDataSourceHandler; | ||||||
|  | import top.continew.starter.extension.tenant.config.TenantProvider; | ||||||
|  | import top.continew.starter.extension.tenant.context.TenantContext; | ||||||
|  | import top.continew.starter.extension.tenant.context.TenantContextHolder; | ||||||
|  | import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 租户工具类 | ||||||
|  |  * | ||||||
|  |  * @author 小熊 | ||||||
|  |  * @author Charles7c | ||||||
|  |  * @since 2.13.1 | ||||||
|  |  */ | ||||||
|  | public class TenantUtils { | ||||||
|  |  | ||||||
|  |     private TenantUtils() { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 使用指定租户执行业务逻辑 | ||||||
|  |      * | ||||||
|  |      * <p> | ||||||
|  |      * 强制设置 {@code TenantContextHolder.setIgnore(false)},执行完恢复原值。<br> | ||||||
|  |      * 适用于在非租户逻辑中执行有租户逻辑的业务逻辑。 | ||||||
|  |      * </p> | ||||||
|  |      * | ||||||
|  |      * @param tenantId 租户 ID | ||||||
|  |      * @param runnable 业务逻辑 | ||||||
|  |      */ | ||||||
|  |     public static void execute(Long tenantId, Runnable runnable) { | ||||||
|  |         // 未启用租户,直接执行业务逻辑 | ||||||
|  |         if (TenantContextHolder.isTenantDisabled()) { | ||||||
|  |             runnable.run(); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         // 原租户上下文 | ||||||
|  |         TenantContext oldContext = TenantContextHolder.getContext(); | ||||||
|  |         boolean oldIgnore = TenantContextHolder.isIgnore(); | ||||||
|  |         boolean isPush = false; | ||||||
|  |         try { | ||||||
|  |             TenantContext newContext = SpringUtil.getBean(TenantProvider.class) | ||||||
|  |                 .getByTenantId(tenantId.toString(), false); | ||||||
|  |             // 设置新租户上下文 | ||||||
|  |             TenantContextHolder.setContext(newContext); | ||||||
|  |             TenantContextHolder.setIgnore(false); | ||||||
|  |             // 数据源级隔离:切换数据源 | ||||||
|  |             if (TenantIsolationLevel.DATASOURCE.equals(newContext.getIsolationLevel())) { | ||||||
|  |                 SpringUtil.getBean(TenantDataSourceHandler.class).changeDataSource(newContext.getDataSource()); | ||||||
|  |                 isPush = true; | ||||||
|  |             } | ||||||
|  |             // 执行业务逻辑 | ||||||
|  |             runnable.run(); | ||||||
|  |         } finally { | ||||||
|  |             // 恢复原租户上下文 | ||||||
|  |             TenantContextHolder.setContext(oldContext); | ||||||
|  |             TenantContextHolder.setIgnore(oldIgnore); | ||||||
|  |             if (isPush) { | ||||||
|  |                 SpringUtil.getBean(TenantDataSourceHandler.class).poll(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 忽略租户执行业务逻辑 | ||||||
|  |      * | ||||||
|  |      * <p> | ||||||
|  |      * 适用于在租户逻辑中执行非租户逻辑的业务逻辑。 | ||||||
|  |      * </p> | ||||||
|  |      * | ||||||
|  |      * @param runnable 业务逻辑 | ||||||
|  |      */ | ||||||
|  |     public void executeIgnore(Runnable runnable) { | ||||||
|  |         // 未启用租户,直接执行业务逻辑 | ||||||
|  |         if (TenantContextHolder.isTenantDisabled()) { | ||||||
|  |             runnable.run(); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         boolean oldIgnore = TenantContextHolder.isIgnore(); | ||||||
|  |         try { | ||||||
|  |             TenantContextHolder.setIgnore(true); | ||||||
|  |             // 执行业务逻辑 | ||||||
|  |             runnable.run(); | ||||||
|  |         } finally { | ||||||
|  |             TenantContextHolder.setIgnore(oldIgnore); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -25,16 +25,13 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; | |||||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |  | ||||||
| import org.springframework.boot.context.properties.EnableConfigurationProperties; | import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.core.ResolvableType; | import org.springframework.core.ResolvableType; | ||||||
| import top.continew.starter.core.constant.PropertiesConstants; | import top.continew.starter.extension.tenant.annotation.ConditionalOnEnabledTenant; | ||||||
| import top.continew.starter.extension.tenant.aop.TenantIgnoreAspect; | import top.continew.starter.extension.tenant.aop.TenantIgnoreAspect; | ||||||
| import top.continew.starter.extension.tenant.config.TenantProvider; | import top.continew.starter.extension.tenant.config.TenantProvider; | ||||||
| import top.continew.starter.extension.tenant.handler.DefaultTenantHandler; |  | ||||||
| import top.continew.starter.extension.tenant.TenantDataSourceHandler; | import top.continew.starter.extension.tenant.TenantDataSourceHandler; | ||||||
| import top.continew.starter.extension.tenant.TenantHandler; |  | ||||||
| import top.continew.starter.extension.tenant.handler.datasource.DefaultTenantDataSourceHandler; | import top.continew.starter.extension.tenant.handler.datasource.DefaultTenantDataSourceHandler; | ||||||
| import top.continew.starter.extension.tenant.handler.datasource.TenantDataSourceAdvisor; | import top.continew.starter.extension.tenant.handler.datasource.TenantDataSourceAdvisor; | ||||||
| import top.continew.starter.extension.tenant.handler.datasource.TenantDataSourceInterceptor; | import top.continew.starter.extension.tenant.handler.datasource.TenantDataSourceInterceptor; | ||||||
| @@ -49,8 +46,8 @@ import javax.sql.DataSource; | |||||||
|  * @since 2.7.0 |  * @since 2.7.0 | ||||||
|  */ |  */ | ||||||
| @AutoConfiguration | @AutoConfiguration | ||||||
|  | @ConditionalOnEnabledTenant | ||||||
| @EnableConfigurationProperties(TenantProperties.class) | @EnableConfigurationProperties(TenantProperties.class) | ||||||
| @ConditionalOnProperty(prefix = PropertiesConstants.TENANT, name = PropertiesConstants.ENABLED, havingValue = "true", matchIfMissing = true) |  | ||||||
| public class TenantAutoConfiguration { | public class TenantAutoConfiguration { | ||||||
|  |  | ||||||
|     private static final Logger log = LoggerFactory.getLogger(TenantAutoConfiguration.class); |     private static final Logger log = LoggerFactory.getLogger(TenantAutoConfiguration.class); | ||||||
| @@ -130,15 +127,6 @@ public class TenantAutoConfiguration { | |||||||
|         throw new NoSuchBeanDefinitionException(TenantProvider.class); |         throw new NoSuchBeanDefinitionException(TenantProvider.class); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 租户处理器 |  | ||||||
|      */ |  | ||||||
|     @Bean |  | ||||||
|     @ConditionalOnMissingBean |  | ||||||
|     public TenantHandler tenantHandler(TenantProvider tenantProvider) { |  | ||||||
|         return new DefaultTenantHandler(tenantProperties, tenantProvider); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @PostConstruct |     @PostConstruct | ||||||
|     public void postConstruct() { |     public void postConstruct() { | ||||||
|         log.debug("[ContiNew Starter] - Auto Configuration 'Tenant' completed initialization."); |         log.debug("[ContiNew Starter] - Auto Configuration 'Tenant' completed initialization."); | ||||||
|   | |||||||
| @@ -1,76 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. |  | ||||||
|  * <p> |  | ||||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; |  | ||||||
|  * you may not use this file except in compliance with the License. |  | ||||||
|  * You may obtain a copy of the License at |  | ||||||
|  * <p> |  | ||||||
|  * http://www.gnu.org/licenses/lgpl.html |  | ||||||
|  * <p> |  | ||||||
|  * Unless required by applicable law or agreed to in writing, software |  | ||||||
|  * distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
|  * See the License for the specific language governing permissions and |  | ||||||
|  * limitations under the License. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| package top.continew.starter.extension.tenant.handler; |  | ||||||
|  |  | ||||||
| import cn.hutool.extra.spring.SpringUtil; |  | ||||||
| import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; |  | ||||||
| import top.continew.starter.extension.tenant.TenantDataSourceHandler; |  | ||||||
| import top.continew.starter.extension.tenant.TenantHandler; |  | ||||||
| import top.continew.starter.extension.tenant.autoconfigure.TenantProperties; |  | ||||||
| import top.continew.starter.extension.tenant.config.TenantProvider; |  | ||||||
| import top.continew.starter.extension.tenant.context.TenantContext; |  | ||||||
| import top.continew.starter.extension.tenant.context.TenantContextHolder; |  | ||||||
| import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 租户处理器 |  | ||||||
|  * |  | ||||||
|  * @author 小熊 |  | ||||||
|  * @since 2.8.0 |  | ||||||
|  */ |  | ||||||
| public class DefaultTenantHandler implements TenantHandler { |  | ||||||
|  |  | ||||||
|     private final TenantProperties tenantProperties; |  | ||||||
|     private final TenantProvider tenantProvider; |  | ||||||
|  |  | ||||||
|     public DefaultTenantHandler(TenantProperties tenantProperties, TenantProvider tenantProvider) { |  | ||||||
|         this.tenantProperties = tenantProperties; |  | ||||||
|         this.tenantProvider = tenantProvider; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void execute(Long tenantId, Runnable runnable) { |  | ||||||
|         if (!tenantProperties.isEnabled()) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         TenantContext tenantContext = tenantProvider.getByTenantId(tenantId.toString(), false); |  | ||||||
|         // 保存当前的租户上下文 |  | ||||||
|         TenantContext originalContext = TenantContextHolder.getContext(); |  | ||||||
|         boolean isPush = false; |  | ||||||
|         try { |  | ||||||
|             // 设置新的租户上下文 |  | ||||||
|             TenantContextHolder.setContext(tenantContext); |  | ||||||
|             // 切换数据源 |  | ||||||
|             if (TenantIsolationLevel.DATASOURCE.equals(tenantContext.getIsolationLevel())) { |  | ||||||
|                 SpringUtil.getBean(TenantDataSourceHandler.class).changeDataSource(tenantContext.getDataSource()); |  | ||||||
|                 isPush = true; |  | ||||||
|             } |  | ||||||
|             // 执行业务逻辑 |  | ||||||
|             runnable.run(); |  | ||||||
|         } finally { |  | ||||||
|             // 恢复原始的租户上下文 |  | ||||||
|             if (originalContext != null) { |  | ||||||
|                 TenantContextHolder.setContext(originalContext); |  | ||||||
|             } else { |  | ||||||
|                 TenantContextHolder.clearContext(); |  | ||||||
|             } |  | ||||||
|             if (isPush) { |  | ||||||
|                 DynamicDataSourceContextHolder.poll(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -82,4 +82,9 @@ public class DefaultTenantDataSourceHandler implements TenantDataSourceHandler { | |||||||
|     public void removeDataSource(String dataSourceName) { |     public void removeDataSource(String dataSourceName) { | ||||||
|         dynamicRoutingDataSource.removeDataSource(dataSourceName); |         dynamicRoutingDataSource.removeDataSource(dataSourceName); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void poll() { | ||||||
|  |         DynamicDataSourceContextHolder.poll(); | ||||||
|  |     } | ||||||
| } | } | ||||||
		Reference in New Issue
	
	Block a user