``` --- 【核心判断】 🔴 这是垃圾代码 - 复杂、低效、有隐藏的递归炸弹 --- 【流程分析:a.b.c.tttt.cn 每层都没备案会怎样】 假设主域名集合包含 cn,那么: 第1轮:直接查询 查询: a.b.c.tttt.cn 返回: false (未备案) ↓ 计算主域名: tttt.cn 生成子域名列表: [b.c.tttt.cn, c.tttt.cn, tttt.cn] 进入第2轮 ↓ 第2轮:递归查子域名(第258行的递归陷阱) 查询: [b.c.tttt.cn, c.tttt.cn, tttt.cn] 全部返回: false ↓ 分别处理: b.c.tttt.cn → 生成 [c.tttt.cn, tttt.cn] c.tttt.cn → 生成 [tttt.cn] tttt.cn → 生成 [] (空!递归终止条件) 合并后查询列表: [c.tttt.cn, tttt.cn, tttt.cn] ← 注意重复! 进入第3轮 ↓ 第3轮:继续递归 查询: [c.tttt.cn, tttt.cn, tttt.cn] ← tttt.cn被查了2次! 全部返回: false ↓ c.tttt.cn → 生成 [tttt.cn] tttt.cn → 生成 [] tttt.cn → 生成 [] 合并后查询列表: [tttt.cn] 进入第4轮 ↓ 第4轮:最后一次 查询: [tttt.cn] 返回: false ↓ tttt.cn → 生成 [] 递归结束! 最终结果 icpMap = { "a.b.c.tttt.cn": "false" // 186行的逻辑会用最后一次子域名查询结果覆盖 } --- 【致命问题】 1️⃣ 隐藏的递归炸弹 (XinAnApiService.java:258) Map domainsICP = getDomainsIcp(subDomains); // 递归! 这他妈是在干什么? - 方法 getDomainsIcp 调用 getSubDomainIcp - getSubDomainIcp 又调用回 getDomainsIcp - 形成递归,但没有任何注释说明! - 递归深度 = 域名层级数 - 1 对于 a.b.c.d.e.f.g.tttt.cn(8层域名): - 会递归 7 次 - 总查询次数:1 + 7 + 6 + 5 + 4 + 3 + 2 + 1 = 28 次调用信安接口! - 而且 tttt.cn 会被重复查询 7 次! 2️⃣ 数据结构错了 - 没有去重! List subDomains = Lists.newArrayList(); subDomainMap.values().forEach(subDomains::addAll); // 256-257行:直接addAll,没去重! tttt.cn 会在 subDomains 列表中出现多次,每次都要查询信安接口。 "Bad programmers worry about the code. Good programmers worry about data structures." - 你需要的是 Set,而不是 List - 或者在查询前去重:subDomains.stream().distinct().collect(Collectors.toList()) 3️⃣ 复杂度爆炸 - 3层缩进是底线,这代码有多少层? 看看第147-158行的嵌套: for (Map.Entry entry : icpMap.entrySet()) { // 第1层 if (StringUtils.isEmpty(icp) || FALSE_ICP.getValue().equals(icp)) { // 第2层 if (CollectionUtils.isEmpty(subDomains)) { // 第3层 continue; } } } 还有异常处理里又重复了一遍逻辑(159-170行)—— 这是什么鬼设计? 4️⃣ getSubDomain 的诡异逻辑 (XinAnApiService.java:358-367) temp.forEach(var -> subDomains.addFirst(StringUtils.join(Arrays.asList(var, subDomains.getFirst()), SEPARATOR2)) ); subDomains.remove(subDomains.getFirst()); // 为什么要先加再删? 为什么不一开始就不加原域名? - 这是在解决不存在的问题 - 应该直接构建正确的列表,而不是"先加后删" --- 【Linus式重构方案】 核心思想:消除递归,用迭代 + 去重 public Map getDomainsIcp(List domains) { if (CollectionUtils.isEmpty(domains)) { return Maps.newHashMap(); } // 第1步:收集所有需要查询的域名(包括子域名),用 Set 去重 Set allDomainsToQuery = new LinkedHashSet<>(); Map> domainHierarchy = new HashMap<>(); for (String domain : domains) { allDomainsToQuery.add(domain); String mainDomain = getDomainParam(domain); List subDomains = getSubDomain(mainDomain, domain); allDomainsToQuery.addAll(subDomains); // Set自动去重 domainHierarchy.put(domain, subDomains); } // 第2步:一次性查询所有域名(去重后) Map allIcpResults = queryDomainsIcpByGroup(new ArrayList<>(allDomainsToQuery)); // 第3步:为每个原始域名找最近的有备案的父域名 Map result = new HashMap<>(); for (String domain : domains) { String icp = allIcpResults.get(domain); // 如果自己有备案,直接用 if (icp != null && !icp.equals(FALSE_ICP.getValue()) && !icp.isEmpty()) { result.put(domain, icp); continue; } // 否则从子域名列表中找第一个有备案的 List subDomains = domainHierarchy.get(domain); boolean found = false; if (subDomains != null) { for (String subDomain : subDomains) { String subIcp = allIcpResults.get(subDomain); if (subIcp != null && !subIcp.equals(FALSE_ICP.getValue()) && !subIcp.isEmpty()) { result.put(domain, subIcp); found = true; break; } } } if (!found) { result.put(domain, icp != null ? icp : ""); } } return result; } 改进效果: | 指标 | 原代码 | 重构后 | |--------------|---------------|-----------| | 递归次数 | N层 | 0 | | 接口调用次数(8层域名) | 28次 | 8次(去重后) | | 重复查询 | 是 | 否 | | 代码行数 | ~80行(分散在3个方法) | ~40行(单方法) | | 可读性 | 需要追踪递归 | 一目了然 | --- 【最后警告】 这段代码有三个经典反模式: 1. "聪明"代码 - 递归隐藏在方法调用里,不看完整代码根本发现不了 2. 重复逻辑 - 异常处理块里复制粘贴了主逻辑 3. 过度抽象 - getSubDomain 方法可以简化成3行,但写成了10行 "Talk is cheap. Show me the code." - 现在代码给你了,你看着办吧。 需要我帮你重构吗?还是你有其他问题? ```