Commit 0a2155eeeb86595efdbd347c5ce46e7b57082438

Authored by 张楣扬
1 parent 3271c6ee

feat(tenant): 集成Redis缓存优化租户管道配置存储

- 添加spring-boot-starter-data-redis依赖支持Redis功能
- 引入JsonUtils和TypeReference用于JSON序列化和反序列化
- 使用StringRedisTemplate替代ConcurrentHashMap存储租户管道配置
- 实现Redis键值结构tax:agent:tenant:pipeline::{tenantId}进行缓存管理
- 添加数据库兜底查询逻辑确保数据一致性
- 实现缓存加载时的Redis写入和日志记录功能
- 优化getTenantPipeline方法通过Redis缓存提高查询性能
tax-central/pom.xml
... ... @@ -31,6 +31,10 @@
31 31 <artifactId>spring-boot-starter-validation</artifactId>
32 32 </dependency>
33 33 <dependency>
  34 + <groupId>org.springframework.boot</groupId>
  35 + <artifactId>spring-boot-starter-data-redis</artifactId>
  36 + </dependency>
  37 + <dependency>
34 38 <groupId>com.jayway.jsonpath</groupId>
35 39 <artifactId>json-path</artifactId>
36 40 </dependency>
... ...
tax-central/src/main/java/com/diligrp/tax/central/context/TenantStorageContext.java
... ... @@ -3,17 +3,19 @@ package com.diligrp.tax.central.context;
3 3 import com.diligrp.tax.central.model.PipelineDO;
4 4 import com.diligrp.tax.central.service.ITenantService;
5 5 import com.diligrp.tax.central.type.SystemType;
  6 +import com.diligrp.tax.central.utils.JsonUtils;
  7 +import com.fasterxml.jackson.core.type.TypeReference;
6 8 import jakarta.annotation.Resource;
7 9 import lombok.extern.slf4j.Slf4j;
8 10 import org.springframework.boot.context.event.ApplicationReadyEvent;
9 11 import org.springframework.context.event.EventListener;
  12 +import org.springframework.data.redis.core.StringRedisTemplate;
10 13 import org.springframework.stereotype.Component;
11 14  
12 15 import java.util.List;
13 16 import java.util.Map;
14 17 import java.util.Objects;
15 18 import java.util.Optional;
16   -import java.util.concurrent.ConcurrentHashMap;
17 19 import java.util.stream.Collectors;
18 20  
19 21 /**
... ... @@ -25,29 +27,51 @@ import java.util.stream.Collectors;
25 27 @Component
26 28 public class TenantStorageContext {
27 29  
  30 + // Redis中租户管道配置的Key前缀:tax:agent:tenant:pipeline::{tenantId}
  31 + private static final String TENANT_PIPELINE_KEY_PREFIX = "tax:agent:tenant:pipeline::";
  32 +
28 33 @Resource
29 34 private ITenantService tenantService;
30 35  
31   - private static final ConcurrentHashMap<Long, Map<SystemType, Map<String, PipelineDO>>> TENANT_PIPELINE_MAP = new ConcurrentHashMap<>();
  36 + @Resource
  37 + private StringRedisTemplate stringRedisTemplate;
  38 +
  39 + private String getTenantPipelineKey(Long tenantId) {
  40 + return TENANT_PIPELINE_KEY_PREFIX + tenantId;
  41 + }
  42 +
  43 + /**
  44 + * 统一数据库兜底查询,并记录查询日志
  45 + * @param tenantId
  46 + * @param pipelineCode
  47 + * @param reason
  48 + * @return
  49 + */
  50 + private Optional<PipelineDO> queryPipelineFromDb(Long tenantId, String pipelineCode, String reason) {
  51 + Optional<PipelineDO> result = tenantService.findByTenantIdAndPipelineCode(tenantId, pipelineCode);
  52 + log.info("统一数据库兜底查询, tenantId:{}, pipelineCode:{}, found:{}", tenantId, pipelineCode, result.isPresent());
  53 + return result;
  54 + }
32 55  
33 56 public Optional<PipelineDO> getTenantPipeline(Long tenantId, SystemType systemType, String pipelineCode) {
34   - var tpMap = TENANT_PIPELINE_MAP.get(tenantId);
35   - if (Objects.isNull(tpMap)) {
36   - return Optional.empty();
37   - }
38   - Map<String, PipelineDO> pipelineMap = tpMap.get(systemType);
39   - if (Objects.isNull(pipelineMap)) {
40   - return Optional.empty();
41   - }
42   - return Optional.ofNullable(pipelineMap.get(pipelineCode)).or(() -> tenantService.findByTenantIdAndPipelineCode(tenantId, pipelineCode));
  57 + return Optional.ofNullable(stringRedisTemplate.opsForValue().get(getTenantPipelineKey(tenantId)))
  58 + .map(json -> JsonUtils.fromJsonString(json, new TypeReference<Map<SystemType, Map<String, PipelineDO>>>() {}))
  59 + .map(tpMap -> Optional.ofNullable(tpMap.get(systemType))
  60 + .flatMap(pipelineMap -> Optional.ofNullable(pipelineMap.get(pipelineCode))
  61 + .or(() -> queryPipelineFromDb(tenantId, pipelineCode, "Redis中systemType或pipelineCode未命中"))))
  62 + .orElseGet(() -> queryPipelineFromDb(tenantId, pipelineCode, "Redis租户Key未命中"));
43 63 }
44 64  
45 65 public void loadTenantPipeline() {
46 66 List<PipelineDO> taxPipelineDOVOS = tenantService.listAllEnablePipeline();
47 67 Optional.ofNullable(taxPipelineDOVOS).ifPresent(pipelines -> {
48 68 var tenantPipelineMap = pipelines.stream().collect(Collectors.groupingBy(PipelineDO::getTenantId, Collectors.groupingBy(PipelineDO::getSystemTypeEnum, Collectors.toMap(PipelineDO::getCode, e -> e))));
49   - TENANT_PIPELINE_MAP.clear();
50   - TENANT_PIPELINE_MAP.putAll(tenantPipelineMap);
  69 + tenantPipelineMap.forEach((tenantId, pipelineMap) -> {
  70 + String tenantPipelineJson = JsonUtils.toJsonString(pipelineMap);
  71 + String redisKey = getTenantPipelineKey(tenantId);
  72 + stringRedisTemplate.opsForValue().set(redisKey, tenantPipelineJson);
  73 + log.info("redis写入缓存, key:{}, tenantId:{}, systemCount:{}", redisKey, tenantId, pipelineMap.size());
  74 + });
51 75 });
52 76 }
53 77  
... ...