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 | 1 | package cn.iocoder.yudao.framework.tenant.config; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.annotation.AnnotationUtil; | |
| 4 | 3 | import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; |
| 5 | 4 | import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; |
| 6 | -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | |
| 7 | 5 | import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; |
| 8 | 6 | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; |
| 9 | 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 | 9 | import cn.iocoder.yudao.framework.tenant.core.mq.TenantRedisMessageInterceptor; |
| 13 | 10 | import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager; |
| 14 | 11 | import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; |
| ... | ... | @@ -20,8 +17,6 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; |
| 20 | 17 | import cn.iocoder.yudao.module.system.api.tenant.TenantApi; |
| 21 | 18 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| 22 | 19 | import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; |
| 23 | -import org.springframework.beans.BeansException; | |
| 24 | -import org.springframework.beans.factory.config.BeanPostProcessor; | |
| 25 | 20 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 26 | 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| 27 | 22 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| ... | ... | @@ -100,25 +95,8 @@ public class YudaoTenantAutoConfiguration { |
| 100 | 95 | // ========== Job ========== |
| 101 | 96 | |
| 102 | 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 | 102 | // ========== Redis ========== | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java
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 | 1 | package cn.iocoder.yudao.framework.tenant.core.job; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.exceptions.ExceptionUtil; | |
| 4 | 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 | 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 | 14 | import java.util.List; |
| 11 | 15 | import java.util.Map; |
| 12 | 16 | import java.util.concurrent.ConcurrentHashMap; |
| 13 | 17 | |
| 14 | 18 | /** |
| 15 | - * 多租户 JobHandler 装饰器 | |
| 19 | + * 多租户 JobHandler AOP | |
| 16 | 20 | * 任务执行时,会按照租户逐个执行 Job 的逻辑 |
| 17 | 21 | * |
| 18 | 22 | * 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。 |
| 19 | 23 | * |
| 20 | 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 | 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 | 36 | List<Long> tenantIds = tenantFrameworkService.getTenantIds(); |
| 35 | 37 | if (CollUtil.isEmpty(tenantIds)) { |
| ... | ... | @@ -38,19 +40,15 @@ public class TenantJobHandlerDecorator implements JobHandler { |
| 38 | 40 | |
| 39 | 41 | // 逐个租户,执行 Job |
| 40 | 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 | 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 | 11 | import java.util.List; |
| 12 | 12 | |
| 13 | 13 | @Component |
| 14 | -@TenantJob // 标记多租户 | |
| 15 | 14 | public class DemoJob implements JobHandler { |
| 16 | 15 | |
| 17 | 16 | @Resource |
| 18 | 17 | private AdminUserMapper adminUserMapper; |
| 19 | 18 | |
| 20 | 19 | @Override |
| 21 | - public String execute(String param) throws Exception { | |
| 20 | + @TenantJob // 标记多租户 | |
| 21 | + public String execute(String param) { | |
| 22 | 22 | System.out.println("当前租户:" + TenantContextHolder.getTenantId()); |
| 23 | 23 | List<AdminUserDO> users = adminUserMapper.selectList(); |
| 24 | 24 | return "用户数量:" + users.size(); | ... | ... |