From ebb3a04251305d3e3cd5d220f267bd4b45a783c2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 16 Sep 2023 14:06:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A4=9A=E7=A7=9F=E6=88=B7?= =?UTF-8?q?=20Job=20=E7=9A=84=E5=AE=9E=E7=8E=B0=EF=BC=8C=E9=87=87=E7=94=A8?= =?UTF-8?q?=20AOP=20=E6=9B=BF=E4=BB=A3=20BeanPostProcessor=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E5=90=AF=E5=8A=A8=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/YudaoTenantAutoConfiguration.java | 28 +-------- .../framework/tenant/core/job/TenantJob.java | 2 +- .../tenant/core/job/TenantJobAspect.java | 56 ++++++++++++++++++ .../core/job/TenantJobHandlerDecorator.java | 58 ------------------- .../yudao/module/system/job/DemoJob.java | 4 +- 5 files changed, 62 insertions(+), 86 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobHandlerDecorator.java diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java index cd4193abf..a632aab7a 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java @@ -1,14 +1,11 @@ package cn.iocoder.yudao.framework.tenant.config; -import cn.hutool.core.annotation.AnnotationUtil; import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; -import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; -import cn.iocoder.yudao.framework.tenant.core.job.TenantJobHandlerDecorator; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect; import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor; import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager; import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; @@ -20,8 +17,6 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.module.system.api.tenant.TenantApi; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -100,25 +95,8 @@ public class YudaoTenantAutoConfiguration { // ========== Job ========== @Bean - @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") - public BeanPostProcessor jobHandlerBeanPostProcessor(TenantFrameworkService tenantFrameworkService) { - return new BeanPostProcessor() { - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if (!(bean instanceof JobHandler)) { - return bean; - } - // 有 TenantJob 注解的情况下,才会进行处理 - if (!AnnotationUtil.hasAnnotation(bean.getClass(), TenantJob.class)) { - return bean; - } - - // 使用 TenantJobHandlerDecorator 装饰 - return new TenantJobHandlerDecorator(tenantFrameworkService, (JobHandler) bean); - } - - }; + public TenantJobAspect tenantJobAspect(TenantFrameworkService tenantFrameworkService) { + return new TenantJobAspect(tenantFrameworkService); } // ========== Redis ========== diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java index fd2ecada9..23474bbe4 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java @@ -8,7 +8,7 @@ import java.lang.annotation.Target; /** * 多租户 Job 注解 */ -@Target({ElementType.TYPE}) +@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface TenantJob { } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java new file mode 100644 index 000000000..732a0732e --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.framework.tenant.core.job; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 多租户 JobHandler AOP + * 任务执行时,会按照租户逐个执行 Job 的逻辑 + * + * 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。 + * + * @author 芋道源码 + */ +@Aspect +@RequiredArgsConstructor +@Slf4j +public class TenantJobAspect { + + private final TenantFrameworkService tenantFrameworkService; + + @Around("@annotation(tenantJob)") + public String around(ProceedingJoinPoint joinPoint, TenantJob tenantJob) { + // 获得租户列表 + List tenantIds = tenantFrameworkService.getTenantIds(); + if (CollUtil.isEmpty(tenantIds)) { + return null; + } + + // 逐个租户,执行 Job + Map results = new ConcurrentHashMap<>(); + tenantIds.parallelStream().forEach(tenantId -> { + // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况 + TenantUtils.execute(tenantId, () -> { + try { + joinPoint.proceed(); + } catch (Throwable e) { + results.put(tenantId, ExceptionUtil.getRootCauseMessage(e)); + } + }); + }); + return JsonUtils.toJsonString(results); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobHandlerDecorator.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobHandlerDecorator.java deleted file mode 100644 index 25a6e016d..000000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobHandlerDecorator.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.iocoder.yudao.framework.tenant.core.job; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; -import lombok.AllArgsConstructor; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 多租户 JobHandler 装饰器 - * 任务执行时,会按照租户逐个执行 Job 的逻辑 - * - * 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。 - * - * @author 芋道源码 - */ -@AllArgsConstructor -public class TenantJobHandlerDecorator implements JobHandler { - - private final TenantFrameworkService tenantFrameworkService; - /** - * 被装饰的 Job - */ - private final JobHandler jobHandler; - - @Override - public final String execute(String param) throws Exception { - // 获得租户列表 - List tenantIds = tenantFrameworkService.getTenantIds(); - if (CollUtil.isEmpty(tenantIds)) { - return null; - } - - // 逐个租户,执行 Job - Map results = new ConcurrentHashMap<>(); - tenantIds.parallelStream().forEach(tenantId -> { // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况 - try { - // 设置租户 - TenantContextHolder.setTenantId(tenantId); - // 执行 Job - String result = jobHandler.execute(param); - // 添加结果 - results.put(tenantId, result); - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - TenantContextHolder.clear(); - } - }); - return JsonUtils.toJsonString(results); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/DemoJob.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/DemoJob.java index fc205b53b..70bb92a2b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/DemoJob.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/DemoJob.java @@ -11,14 +11,14 @@ import javax.annotation.Resource; import java.util.List; @Component -@TenantJob // 标记多租户 public class DemoJob implements JobHandler { @Resource private AdminUserMapper adminUserMapper; @Override - public String execute(String param) throws Exception { + @TenantJob // 标记多租户 + public String execute(String param) { System.out.println("当前租户:" + TenantContextHolder.getTenantId()); List users = adminUserMapper.selectList(); return "用户数量:" + users.size();