From 07e1637363bce4cac3f215384c8bbf6235a30778 Mon Sep 17 00:00:00 2001 From: Charles7c Date: Wed, 16 Jul 2025 22:44:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(extension/tenant):=20=E6=96=B0=E5=A2=9E=20?= =?UTF-8?q?TenantIgnoreAspect=20=E5=88=87=E9=9D=A2=EF=BC=8C=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E7=AD=89=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E5=BF=BD=E7=95=A5=E7=A7=9F=E6=88=B7=E7=9A=84=E5=9C=BA?= =?UTF-8?q?=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tenant/annotation/TenantIgnore.java | 4 ++ .../tenant/aop/TenantIgnoreAspect.java | 51 +++++++++++++++++++ .../autoconfigure/TenantInterceptor.java | 10 +++- .../tenant/context/TenantContextHolder.java | 37 ++++++++++++-- .../TenantAutoConfiguration.java | 10 ++++ .../datasource/TenantDataSourceAdvisor.java | 1 - .../TenantDataSourceInterceptor.java | 5 ++ .../line/DefaultTenantLineHandler.java | 18 +++++-- 8 files changed, 125 insertions(+), 11 deletions(-) create mode 100644 continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/aop/TenantIgnoreAspect.java diff --git a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/annotation/TenantIgnore.java b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/annotation/TenantIgnore.java index 43a8600a..10b8fa22 100644 --- a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/annotation/TenantIgnore.java +++ b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/annotation/TenantIgnore.java @@ -21,6 +21,10 @@ import java.lang.annotation.*; /** * 租户忽略注解 * + *

+ * 例如:定时任务等需要忽略租户的场景 + *

+ * * @author Charles7c * @since 2.7.0 */ diff --git a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/aop/TenantIgnoreAspect.java b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/aop/TenantIgnoreAspect.java new file mode 100644 index 00000000..773c0648 --- /dev/null +++ b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/aop/TenantIgnoreAspect.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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.aop; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import top.continew.starter.extension.tenant.annotation.TenantIgnore; +import top.continew.starter.extension.tenant.context.TenantContextHolder; + +/** + * 租户忽略注解切面 + * + * @author Charles7c + * @since 2.13.1 + */ +@Aspect +public class TenantIgnoreAspect { + + /** + * 忽略租户 + * + * @param joinPoint 切点 + * @return 返回结果 + * @throws Throwable 异常 + */ + @Around("@annotation(tenantIgnore)") + public Object around(ProceedingJoinPoint joinPoint, TenantIgnore tenantIgnore) throws Throwable { + boolean oldIgnore = TenantContextHolder.isIgnore(); + try { + TenantContextHolder.setIgnore(true); + return joinPoint.proceed(); + } finally { + TenantContextHolder.setIgnore(oldIgnore); + } + } +} diff --git a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/autoconfigure/TenantInterceptor.java b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/autoconfigure/TenantInterceptor.java index 705c8cf8..0c26ae5f 100644 --- a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/autoconfigure/TenantInterceptor.java +++ b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/autoconfigure/TenantInterceptor.java @@ -16,6 +16,7 @@ package top.continew.starter.extension.tenant.autoconfigure; +import cn.hutool.core.annotation.AnnotationUtil; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.core.Ordered; @@ -44,8 +45,13 @@ public class TenantInterceptor implements HandlerInterceptor, Ordered { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (handler instanceof HandlerMethod handlerMethod) { - TenantIgnore tenantIgnore = handlerMethod.getMethodAnnotation(TenantIgnore.class); - if (tenantIgnore != null) { + TenantIgnore methodAnnotation = handlerMethod.getMethodAnnotation(TenantIgnore.class); + if (methodAnnotation != null) { + return true; + } + TenantIgnore classAnnotation = AnnotationUtil.getAnnotation(handlerMethod + .getBeanType(), TenantIgnore.class); + if (classAnnotation != null) { return true; } } diff --git a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/context/TenantContextHolder.java b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/context/TenantContextHolder.java index 9b272cce..ec4018cc 100644 --- a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/context/TenantContextHolder.java +++ b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-core/src/main/java/top/continew/starter/extension/tenant/context/TenantContextHolder.java @@ -32,7 +32,15 @@ import java.util.Optional; */ public class TenantContextHolder { - private static final TransmittableThreadLocal CONTEXT_HOLDER = new TransmittableThreadLocal<>(); + /** + * 租户上下文 + */ + private static final TransmittableThreadLocal CONTEXT = new TransmittableThreadLocal<>(); + + /** + * 是否忽略租户 + */ + private static final TransmittableThreadLocal IGNORE = new TransmittableThreadLocal<>(); private TenantContextHolder() { } @@ -43,7 +51,7 @@ public class TenantContextHolder { * @param context 上下文 */ public static void setContext(TenantContext context) { - CONTEXT_HOLDER.set(context); + CONTEXT.set(context); } /** @@ -52,14 +60,33 @@ public class TenantContextHolder { * @return 上下文 */ public static TenantContext getContext() { - return CONTEXT_HOLDER.get(); + return CONTEXT.get(); } /** - * 清除上下文 + * 设置是否忽略租户 + * + * @param ignore 是否忽略租户 + */ + public static void setIgnore(boolean ignore) { + IGNORE.set(ignore); + } + + /** + * 是否忽略租户 + * + * @return 是否忽略租户 + */ + public static boolean isIgnore() { + return Boolean.TRUE.equals(IGNORE.get()); + } + + /** + * 清除 */ public static void clearContext() { - CONTEXT_HOLDER.remove(); + CONTEXT.remove(); + IGNORE.remove(); } /** diff --git a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/autoconfigure/TenantAutoConfiguration.java b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/autoconfigure/TenantAutoConfiguration.java index d493beb3..a4af40e5 100644 --- a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/autoconfigure/TenantAutoConfiguration.java +++ b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/autoconfigure/TenantAutoConfiguration.java @@ -30,6 +30,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean; import org.springframework.core.ResolvableType; import top.continew.starter.core.constant.PropertiesConstants; +import top.continew.starter.extension.tenant.aop.TenantIgnoreAspect; import top.continew.starter.extension.tenant.config.TenantProvider; import top.continew.starter.extension.tenant.handler.DefaultTenantHandler; import top.continew.starter.extension.tenant.TenantDataSourceHandler; @@ -59,6 +60,15 @@ public class TenantAutoConfiguration { this.tenantProperties = tenantProperties; } + /** + * 租户忽略切面 + */ + @Bean + @ConditionalOnMissingBean + public TenantIgnoreAspect tenantIgnoreAspect() { + return new TenantIgnoreAspect(); + } + /** * 租户行级隔离拦截器 */ diff --git a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/datasource/TenantDataSourceAdvisor.java b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/datasource/TenantDataSourceAdvisor.java index 88b530a3..e1703760 100644 --- a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/datasource/TenantDataSourceAdvisor.java +++ b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/datasource/TenantDataSourceAdvisor.java @@ -67,7 +67,6 @@ public class TenantDataSourceAdvisor extends AbstractPointcutAdvisor implements AspectJExpressionPointcut cut = new AspectJExpressionPointcut(); cut.setExpression(""" execution(* *..controller..*(..)) - && !@annotation(top.continew.starter.extension.tenant.annotation.TenantIgnore) """); return new ComposablePointcut((Pointcut)cut); } diff --git a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/datasource/TenantDataSourceInterceptor.java b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/datasource/TenantDataSourceInterceptor.java index 1592e84d..f1d8fac7 100644 --- a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/datasource/TenantDataSourceInterceptor.java +++ b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/datasource/TenantDataSourceInterceptor.java @@ -39,6 +39,11 @@ public class TenantDataSourceInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { + // 忽略租户 + if (TenantContextHolder.isIgnore()) { + return true; + } + // 忽略行级隔离 if (TenantIsolationLevel.LINE.equals(TenantContextHolder.getIsolationLevel())) { return invocation.proceed(); } diff --git a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/line/DefaultTenantLineHandler.java b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/line/DefaultTenantLineHandler.java index f17e1269..fb373b75 100644 --- a/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/line/DefaultTenantLineHandler.java +++ b/continew-starter-extension/continew-starter-extension-tenant/continew-starter-extension-tenant-mp/src/main/java/top/continew/starter/extension/tenant/handler/line/DefaultTenantLineHandler.java @@ -20,6 +20,9 @@ import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.NullValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import top.continew.starter.extension.tenant.autoconfigure.TenantProperties; import top.continew.starter.extension.tenant.context.TenantContextHolder; import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; @@ -32,6 +35,7 @@ import top.continew.starter.extension.tenant.enums.TenantIsolationLevel; */ public class DefaultTenantLineHandler implements TenantLineHandler { + private static final Logger log = LoggerFactory.getLogger(DefaultTenantLineHandler.class); private final TenantProperties tenantProperties; public DefaultTenantLineHandler(TenantProperties tenantProperties) { @@ -44,7 +48,8 @@ public class DefaultTenantLineHandler implements TenantLineHandler { if (tenantId != null) { return new LongValue(tenantId); } - return null; + log.warn("Tenant ID not found in current context."); + return new NullValue(); } @Override @@ -54,13 +59,20 @@ public class DefaultTenantLineHandler implements TenantLineHandler { @Override public boolean ignoreTable(String tableName) { - Long tenantId = TenantContextHolder.getTenantId(); - if (tenantId != null && tenantId.equals(tenantProperties.getSuperTenantId())) { + // 忽略租户 + if (TenantContextHolder.isIgnore()) { return true; } + // 忽略超级租户 + Long tenantId = TenantContextHolder.getTenantId(); + if (tenantId == null || tenantId.equals(tenantProperties.getSuperTenantId())) { + return true; + } + // 忽略数据源级隔离 if (TenantIsolationLevel.DATASOURCE.equals(TenantContextHolder.getIsolationLevel())) { return true; } + // 忽略指定表 return CollUtil.contains(tenantProperties.getIgnoreTables(), tableName); } } \ No newline at end of file