Skip to content

[Bug] Spring Bean 名称解析会被前缀注解和相邻组件注解污染 #315

Description

@1lck

Platform / 平台

Rust Core(macOS / Windows 共用)

Lithe version / Lithe 版本

0cdc30b#306 合并提交)

OS and architecture / 操作系统与架构

平台无关,问题位于 rust/lithe-core/src/languages/spring.rs

Environment / 环境信息

这是 #299#306 的后续问题。#306 已把 Spring 索引热路径上的固定正则改为进程级缓存,并为已登记注解补上准确的名称边界;合并后的复核发现,Bean 名称提取仍保留了两条较宽松的旧路径。

这两个行为在 #306 之前已经存在,不代表性能修复需要回滚,但应作为独立的解析正确性修复跟进。

Steps to reproduce / 复现步骤

场景一:@Bean 前缀诱饵污染名称

让同一个注解上下文同时包含一个前缀相同的自定义注解和真实 @Bean

@BeanFactory("decoy") @Bean("real")
public Clock clock() { return null; }

当前检测阶段会通过 SpringAnnotation::Bean.is_present(context) 正确确认真实 @Bean 存在,但 bean_names 随后仍执行:

context.find("@Bean")

因此名称提取从 @BeanFactory 开始,最终返回 decoy

场景二:多个组件注解的参数被跨注解捕获

@Service("s") @Component("c")
public class Demo {}

当前 component_name 的正则可能从第一个注解的闭合引号开始,继续跨过右括号和第二个注解,最终得到垃圾名称:

) @Component(

另外,COMPONENTS 上方注释声称数组顺序决定多个注解谁获胜。Rust regex 实际先选择输入中位置最靠左的匹配;这些注解名称又互不构成前缀,因此调整数组顺序不会改变结果。该注释需要一起修正。

Expected behavior / 预期行为

  • Bean 名称只能从准确匹配的 @Bean 注解参数中提取,示例一应得到 real
  • 组件名称不能跨越当前注解的右括号读取后续注解。
  • 多个组件注解同时存在时应采用明确且可测试的规则。推荐按源码顺序选择第一个准确匹配的组件注解,示例二得到 s
  • 未显式命名时继续使用当前默认名称逻辑。

Actual behavior / 实际行为

  • bean_names 使用朴素字符串前缀搜索,返回 decoy
  • component_name 的捕获范围可能跨越相邻注解,返回 ) @Component(
  • 新增的 COMPONENTS 注释描述了实际不存在的数组顺序优先级。

Root cause / 根因

  1. 检测阶段已经使用 SpringAnnotation::Bean.pattern() 的准确边界,但命名阶段没有复用同一匹配结果。
  2. component_name 用一个宽范围表达式同时负责选择注解和提取字符串参数,没有先隔离单个注解的参数范围。
  3. Regex alternation 的分支顺序被误认为能覆盖源码位置优先级。

Recommended fix / 推荐修补方案

  1. bean_names 中使用 SpringAnnotation::Bean.pattern().find(context) 定位真实 @Bean,替换 find("@Bean");只在该注解自己的参数范围内调用 quoted_values
  2. 将组件注解的“定位”和“参数解析”拆开:
    • 使用 SpringAnnotation::COMPONENTS 的准确边界模式找到所有候选;
    • Match::start() 选择源码中最靠前的候选;
    • 只扫描该注解对应的一对括号,解析时正确处理字符串和嵌套括号,禁止越过注解边界。
  3. 删除 COMPONENTS 注释中“数组顺序决定胜者”的描述,改为说明集合只负责保持检测和命名支持范围一致。
  4. 不要在逐行热路径重新调用 Regex::new;继续复用 perf(core): Spring 索引正则改为只编译一次,491.74s 降至 2.40s #306 引入的 LazyLock 模式。

如果为了控制改动规模暂时不处理完整的括号扫描,至少应让名称捕获中的字符范围无法跨过当前右括号,并用下面的组合场景锁住行为。

Required tests / 必需测试

  • @BeanFactory("decoy") @Bean("real") 只返回 real
  • 单独的 @BeanFactory("decoy") 不生成 Bean。
  • @Service("s") @Component("c") 不产生跨注解字符串,并按约定返回 s
  • 反转 COMPONENTS 数组不会改变按源码位置选择的结果。
  • 六种组件注解各自的单注解命名测试继续通过。
  • 无参数注解继续走默认 Bean 名称。

Acceptance criteria / 验收标准

Related / 关联

Checklist / 提交前检查

  • I searched existing issues for duplicates. / 我已搜索现有 Issue,确认没有重复报告。
  • I removed secrets and personal data from the report. / 我已从报告中移除敏感信息和个人数据。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions