Commit ebb3a04251305d3e3cd5d220f267bd4b45a783c2
1 parent
6a371f06
优化多租户 Job 的实现,采用 AOP 替代 BeanPostProcessor,提升启动速度
Showing
4 changed files
with
29 additions
and
53 deletions
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
| 1 | package cn.iocoder.yudao.framework.tenant.config; | 1 | package cn.iocoder.yudao.framework.tenant.config; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.annotation.AnnotationUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; | 3 | import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; | 4 | import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; |
| 6 | -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | ||
| 7 | import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; | 5 | import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; |
| 8 | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; | 6 | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; |
| 9 | import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; | 7 | import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; |
| 10 | -import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; | ||
| 11 | -import cn.iocoder.yudao.framework.tenant.core.job.TenantJobHandlerDecorator; | 8 | +import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect; |
| 12 | import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor; | 9 | import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor; |
| 13 | import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager; | 10 | import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager; |
| 14 | import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; | 11 | import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; |
| @@ -20,8 +17,6 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; | @@ -20,8 +17,6 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; | ||
| 20 | import cn.iocoder.yudao.module.system.api.tenant.TenantApi; | 17 | import cn.iocoder.yudao.module.system.api.tenant.TenantApi; |
| 21 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; | 18 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| 22 | import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; | 19 | import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; |
| 23 | -import org.springframework.beans.BeansException; | ||
| 24 | -import org.springframework.beans.factory.config.BeanPostProcessor; | ||
| 25 | import org.springframework.boot.autoconfigure.AutoConfiguration; | 20 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 26 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| 27 | import org.springframework.boot.context.properties.EnableConfigurationProperties; | 22 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| @@ -100,25 +95,8 @@ public class YudaoTenantAutoConfiguration { | @@ -100,25 +95,8 @@ public class YudaoTenantAutoConfiguration { | ||
| 100 | // ========== Job ========== | 95 | // ========== Job ========== |
| 101 | 96 | ||
| 102 | @Bean | 97 | @Bean |
| 103 | - @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") | ||
| 104 | - public BeanPostProcessor jobHandlerBeanPostProcessor(TenantFrameworkService tenantFrameworkService) { | ||
| 105 | - return new BeanPostProcessor() { | ||
| 106 | - | ||
| 107 | - @Override | ||
| 108 | - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { | ||
| 109 | - if (!(bean instanceof JobHandler)) { | ||
| 110 | - return bean; | ||
| 111 | - } | ||
| 112 | - // 有 TenantJob 注解的情况下,才会进行处理 | ||
| 113 | - if (!AnnotationUtil.hasAnnotation(bean.getClass(), TenantJob.class)) { | ||
| 114 | - return bean; | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | - // 使用 TenantJobHandlerDecorator 装饰 | ||
| 118 | - return new TenantJobHandlerDecorator(tenantFrameworkService, (JobHandler) bean); | ||
| 119 | - } | ||
| 120 | - | ||
| 121 | - }; | 98 | + public TenantJobAspect tenantJobAspect(TenantFrameworkService tenantFrameworkService) { |
| 99 | + return new TenantJobAspect(tenantFrameworkService); | ||
| 122 | } | 100 | } |
| 123 | 101 | ||
| 124 | // ========== Redis ========== | 102 | // ========== Redis ========== |
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; | @@ -8,7 +8,7 @@ import java.lang.annotation.Target; | ||
| 8 | /** | 8 | /** |
| 9 | * 多租户 Job 注解 | 9 | * 多租户 Job 注解 |
| 10 | */ | 10 | */ |
| 11 | -@Target({ElementType.TYPE}) | 11 | +@Target({ElementType.METHOD}) |
| 12 | @Retention(RetentionPolicy.RUNTIME) | 12 | @Retention(RetentionPolicy.RUNTIME) |
| 13 | public @interface TenantJob { | 13 | public @interface TenantJob { |
| 14 | } | 14 | } |
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobHandlerDecorator.java renamed to yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java
| 1 | package cn.iocoder.yudao.framework.tenant.core.job; | 1 | package cn.iocoder.yudao.framework.tenant.core.job; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.exceptions.ExceptionUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 5 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 5 | -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | ||
| 6 | -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | ||
| 7 | import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; | 6 | import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; |
| 8 | -import lombok.AllArgsConstructor; | 7 | +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| 8 | +import lombok.RequiredArgsConstructor; | ||
| 9 | +import lombok.extern.slf4j.Slf4j; | ||
| 10 | +import org.aspectj.lang.ProceedingJoinPoint; | ||
| 11 | +import org.aspectj.lang.annotation.Around; | ||
| 12 | +import org.aspectj.lang.annotation.Aspect; | ||
| 9 | 13 | ||
| 10 | import java.util.List; | 14 | import java.util.List; |
| 11 | import java.util.Map; | 15 | import java.util.Map; |
| 12 | import java.util.concurrent.ConcurrentHashMap; | 16 | import java.util.concurrent.ConcurrentHashMap; |
| 13 | 17 | ||
| 14 | /** | 18 | /** |
| 15 | - * 多租户 JobHandler 装饰器 | 19 | + * 多租户 JobHandler AOP |
| 16 | * 任务执行时,会按照租户逐个执行 Job 的逻辑 | 20 | * 任务执行时,会按照租户逐个执行 Job 的逻辑 |
| 17 | * | 21 | * |
| 18 | * 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。 | 22 | * 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。 |
| 19 | * | 23 | * |
| 20 | * @author 芋道源码 | 24 | * @author 芋道源码 |
| 21 | */ | 25 | */ |
| 22 | -@AllArgsConstructor | ||
| 23 | -public class TenantJobHandlerDecorator implements JobHandler { | 26 | +@Aspect |
| 27 | +@RequiredArgsConstructor | ||
| 28 | +@Slf4j | ||
| 29 | +public class TenantJobAspect { | ||
| 24 | 30 | ||
| 25 | private final TenantFrameworkService tenantFrameworkService; | 31 | private final TenantFrameworkService tenantFrameworkService; |
| 26 | - /** | ||
| 27 | - * 被装饰的 Job | ||
| 28 | - */ | ||
| 29 | - private final JobHandler jobHandler; | ||
| 30 | 32 | ||
| 31 | - @Override | ||
| 32 | - public final String execute(String param) throws Exception { | 33 | + @Around("@annotation(tenantJob)") |
| 34 | + public String around(ProceedingJoinPoint joinPoint, TenantJob tenantJob) { | ||
| 33 | // 获得租户列表 | 35 | // 获得租户列表 |
| 34 | List<Long> tenantIds = tenantFrameworkService.getTenantIds(); | 36 | List<Long> tenantIds = tenantFrameworkService.getTenantIds(); |
| 35 | if (CollUtil.isEmpty(tenantIds)) { | 37 | if (CollUtil.isEmpty(tenantIds)) { |
| @@ -38,19 +40,15 @@ public class TenantJobHandlerDecorator implements JobHandler { | @@ -38,19 +40,15 @@ public class TenantJobHandlerDecorator implements JobHandler { | ||
| 38 | 40 | ||
| 39 | // 逐个租户,执行 Job | 41 | // 逐个租户,执行 Job |
| 40 | Map<Long, String> results = new ConcurrentHashMap<>(); | 42 | Map<Long, String> results = new ConcurrentHashMap<>(); |
| 41 | - tenantIds.parallelStream().forEach(tenantId -> { // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况 | ||
| 42 | - try { | ||
| 43 | - // 设置租户 | ||
| 44 | - TenantContextHolder.setTenantId(tenantId); | ||
| 45 | - // 执行 Job | ||
| 46 | - String result = jobHandler.execute(param); | ||
| 47 | - // 添加结果 | ||
| 48 | - results.put(tenantId, result); | ||
| 49 | - } catch (Exception e) { | ||
| 50 | - throw new RuntimeException(e); | ||
| 51 | - } finally { | ||
| 52 | - TenantContextHolder.clear(); | ||
| 53 | - } | 43 | + tenantIds.parallelStream().forEach(tenantId -> { |
| 44 | + // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况 | ||
| 45 | + TenantUtils.execute(tenantId, () -> { | ||
| 46 | + try { | ||
| 47 | + joinPoint.proceed(); | ||
| 48 | + } catch (Throwable e) { | ||
| 49 | + results.put(tenantId, ExceptionUtil.getRootCauseMessage(e)); | ||
| 50 | + } | ||
| 51 | + }); | ||
| 54 | }); | 52 | }); |
| 55 | return JsonUtils.toJsonString(results); | 53 | return JsonUtils.toJsonString(results); |
| 56 | } | 54 | } |
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; | @@ -11,14 +11,14 @@ import javax.annotation.Resource; | ||
| 11 | import java.util.List; | 11 | import java.util.List; |
| 12 | 12 | ||
| 13 | @Component | 13 | @Component |
| 14 | -@TenantJob // 标记多租户 | ||
| 15 | public class DemoJob implements JobHandler { | 14 | public class DemoJob implements JobHandler { |
| 16 | 15 | ||
| 17 | @Resource | 16 | @Resource |
| 18 | private AdminUserMapper adminUserMapper; | 17 | private AdminUserMapper adminUserMapper; |
| 19 | 18 | ||
| 20 | @Override | 19 | @Override |
| 21 | - public String execute(String param) throws Exception { | 20 | + @TenantJob // 标记多租户 |
| 21 | + public String execute(String param) { | ||
| 22 | System.out.println("当前租户:" + TenantContextHolder.getTenantId()); | 22 | System.out.println("当前租户:" + TenantContextHolder.getTenantId()); |
| 23 | List<AdminUserDO> users = adminUserMapper.selectList(); | 23 | List<AdminUserDO> users = adminUserMapper.selectList(); |
| 24 | return "用户数量:" + users.size(); | 24 | return "用户数量:" + users.size(); |