news 2026/9/25 2:15:23

analyzer_plugin 变更史解读:Dart 分析服务器插件框架的 API 演进与版本兼容策略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
analyzer_plugin 变更史解读:Dart 分析服务器插件框架的 API 演进与版本兼容策略
  • 编程语言
  • 编译器
  • 语言运行时
  • 标准库
  • 开发工具

【免费下载链接】sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.

项目地址:https://gitcode.com/gh_mirrors/sdk1/sdk
点击查看免费下载

analyzer_plugin是 Dart SDK 中用于构建 analysis server 插件的官方框架,其 CHANGELOG.md 记录了从 0.0.1 到 0.14.18-dev 的完整演进轨迹。本文以该变更日志为核心骨架,结合pkg/analyzer_plugin/lib下的源码实现,系统梳理插件框架的架构、关键 API 的破坏性变更、版本兼容策略,帮助插件开发者理解 API 的来龙去脉,并据此规划插件升级路径。

一、框架定位:为 analysis server 构建插件的支持代码

analyzer_plugin是一套用于构建 analysis server 插件的框架与支持代码。按 README.md 的说明,插件用 Dart 编写,运行在与 analysis server 相同的 VM 中,每个插件运行在独立 isolate 中,通过插件 API(与 analysis server 和客户端通信的 API 类似)与服务器通信,并被服务器自动发现和运行。

从 pubspec.yaml 可以看到,该包除依赖analyzer外,还依赖collection、dart_style、pub_semver、yaml和path,其版本策略声明:"We use 'any' version constraints here as we get our package versions from the dart-lang/sdk repo's DEPS file"。这意味着在 SDK 仓库内联开发时,依赖版本由 DEPS 统一管理。

需要特别说明的是,README 已明确标注该包为legacy support,新插件开发推荐使用analysis_server_plugin包。但对维护既有插件、理解 analysis server 插件协议演进历史的开发者而言,本变更日志仍是权威资料。

二、版本兼容策略:与analyzer包严格对齐

变更日志中超过一半的条目是同一句话的变体——"Require version X of theanalyzerpackage"。这构成了该包最重要的工程策略:每个 analyzer_plugin 版本都严格绑定一个 analyzer 版本范围,二者必须同步升级。

analyzer_plugin 版本要求的 analyzer 版本备注
0.14.18-dev14.5.0-dev当前开发版本
0.14.1714.4.0
0.14.1614.3.0
0.14.1514.2.0
0.14.1414.1.0
0.14.1314.0.0
0.14.1213.3.0
0.14.1113.2.0
0.14.1013.1.0
0.14.913.0.0
0.14.812.1.0
0.14.712.0.0
0.14.6-dev11.1.0-dev
0.14.5^11.0.0-0
0.14.4-dev10.3.0-dev
0.14.410.2.0
0.14.310.1.0
0.14.210.0.2
0.14.110.0.1
0.14.010.0.0本版本含大量破坏性变更(见下文)
0.13.119.0.0
0.13.88.2.0同时要求 Dart SDK^3.9.0
0.13.5^8.0.0
0.13.4^7.5.1
0.13.2^7.4.6同时弃用RangeFactory.error
0.12.07.x协议枚举转为真枚举
0.11.36.x
0.11.25.x
0.10.04.x
0.9.03.x
0.7.02.x
0.5.0^1.3.0稳定版空安全
0.4.0>=0.41.0 <0.42.0
0.2.5^0.39.12
0.2.2^0.39.0
0.2.1<0.39.0同时修复 issue #37916、#38326

可见早期版本约束写法经历了从^0.39.0、<0.39.0到^1.3.0,再到^8.0.0、7.x和精确版本14.4.0的演化。当前仓库中 pubspec.yaml 实际锁定analyzer: 14.5.0-dev,与 0.14.18-dev 条目完全对应。

对于插件作者,这一策略意味着:升级 analyzer_plugin 时必须同步升级 analyzer,二者版本一一对应,不存在跨大版本混用的空间。这也是该包频繁发布小版本、每条记录都只有一行版本声明的原因。

三、插件生命周期与核心基类 ServerPlugin

在 lib/plugin/plugin.dart 中,ServerPlugin是所有插件必须继承的抽象基类。它定义了插件的核心形态:

  • 基本属性:name(用户可见插件名)、version(插件协议版本号)、fileGlobsToAnalyze(插件关注的文件 glob 模式)、contactInfo(作者联系信息,可空)。
  • 通信通道:start(PluginCommunicationChannel channel)启动插件并监听通道;channelgetter 返回当前通信通道。
  • 版本握手:handlePluginVersionCheck处理plugin.versionCheck请求,记录 SDK 路径并返回isCompatibleWith(serverVersion)、插件名、版本与 glob 模式;isCompatibleWith的判定逻辑是serverVersion <= Version.parse(version)。
  • 上下文管理:handleAnalysisSetContextRoots根据客户端下发的根路径创建AnalysisContextCollectionImpl,并在创建后回调afterNewContextCollection执行初始分析;销毁前回调beforeContextCollectionDispose。
  • 文件内容同步:handleAnalysisUpdateContent支持AddContentOverlay、ChangeContentOverlay、RemoveContentOverlay三种 overlay 变更,并将变更路径交给contentChanged,最终触发handleAffectedFiles对受影响文件重分析。
  • 订阅机制:handleAnalysisSetSubscriptions把客户端订阅的服务集合写入subscriptionManager,并立即对新订阅文件发送通知;sendNotificationsForFile按订阅的AnalysisService(FOLDING、HIGHLIGHTS、NAVIGATION、OCCURRENCES、OUTLINE)分发通知。
  • 各功能请求的默认实现:handleAnalysisGetNavigation、handleCompletionGetSuggestions、handleEditGetAssists、handleEditGetFixes、handleEditGetAvailableRefactorings、handleEditGetRefactoring等均返回空结果,子类按需覆写。

启动入口在 lib/starter.dart:ServerPluginStarter工厂创建Driver(plugin),start(SendPort sendPort)建立与服务器通信的通道并启动插件。插件由此运行在独立 isolate 中,与 analysis server 通过 SendPort 交换消息。

ServerPlugin内部还维护了priorityPaths(优先分析文件集合)与ByteStore(跨 AnalysisContext 复用的字节缓存,默认实现为 256MB 内存缓存)。flushAnalysisState可清理元素模型状态以降低堆占用,代价是下次分析会从缓存恢复、速度变慢。

四、分析上下文模型的演进(0.11.0)

0.11.0 的条目写明:

UsingAnalysisContextCollectionandAnalysisContextfor analysis.

这是插件分析模型的一次架构升级。在 0.11.0 之前,插件内部直接基于AnalysisDriver进行文件分析;之后统一改为AnalysisContextCollection(上下文集合)+AnalysisContext(单个上下文)模型。这一模型与 analyzer 包自身的分析驱动一致,使得插件可以按 context root 组织分析单元。

从 plugin.dart 的实现看,handleAnalysisSetContextRoots会基于请求中的includedPaths、resourceProvider、_byteStore、_sdkPath等构造新的AnalysisContextCollectionImpl,并开启withFineDependencies: true以支持细粒度依赖跟踪。contentChanged则对每个上下文调用analysisContext.changeFile(path)与applyPendingFileChanges(),得到受影响文件后再交给handleAffectedFiles。

0.11.1 进一步修正了行为细节:handleAffectedFiles默认仅对该分析上下文中确实被分析的文件调用analyzeFiles。对应实现是 plugin.dart 中的paths.where(analysisContext.contextRoot.isAnalyzed)过滤,避免把不属于当前上下文(如未纳入分析根目录)的文件也纳入分析,减少无效工作。

getResolvedUnitResult(path)是对外暴露的关键方法,通过当前上下文会话调用analysisSession.getResolvedUnit(path)获取ResolvedUnitResult,失败时抛出RequestFailure并返回pluginError。

五、变更构建器(ChangeBuilder)体系的演进

变更构建器是插件为 IDE/编辑器生成代码修改(assists、fixes)的核心设施,也是历次破坏性变更最密集的区域。

5.1 从 DartChangeBuilder 到 ChangeBuilder(0.4.0 → 0.5.0)

0.4.0 引入三个重要变化:

  • 弃用DartChangeBuilder类,增强ChangeBuilder作为替代;
  • 弃用ChangeBuilder.addFileEdit,新增addDartFileEdit与addGenericFileEdit;
  • analyzer 支持范围改为>=0.41.0 <0.42.0。

0.5.0 在稳定空安全(null safety)发布时正式移除DartChangeBuilder、DartChangeBuilderImpl与addFileEdit(),并弃用Plugin.fileContentOverlay——资源提供者统一改为OverlayResourceProvider,由analysis.updateContent更新。

当前 change_builder_core.dart 中,ChangeBuilder的工厂签名要求传入AnalysisSession或ChangeWorkspace(二选一,不能同时),并提供defaultEol参数(默认Platform.lineTerminator,已有 EOL 标记的文件保持原 EOL)。三个文件编辑入口分工明确:

  • addDartFileEdit(path, buildFileEdit):针对 Dart 源文件,builder 具备 Dart 专用能力;createEditsForImports参数(默认true)控制是否自动生成缺失 import 的编辑;
  • addGenericFileEdit(path, buildFileEdit):通用文件,无特殊支持;
  • addYamlFileEdit(path, buildFileEdit):针对 YAML 源文件,builder 具备 YAML 专用能力。

0.14.0 又移除了ChangeBuilder.new已弃用的eol参数与addDartFileEdit已弃用的importPrefixGenerator参数,并删除ChangeBuilder.copy方法。

5.2 DartEditBuilder 的新增 API(0.12.0)

0.12.0 在DartEditBuilder上新增了writeFormalParameter与writeFormalParameters,在DartFileEditBuilder上新增了:

  • getIndent:按层级返回缩进;
  • insertCaseClauseAtEnd:在 switch 语句/表达式末尾插入 case 子句;
  • insertConstructor、insertField、insertGetter、insertMethod:按 lint 规则与代码风格把成员插入到合适位置;
  • writeIndent:写出缩进(每个层级两个空格)。

在 change_builder_dart.dart 中可以确认这些 API 的完整签名与语义。例如insertConstructor会考虑sort_constructors_first、sort_unnamed_constructors_first两条 lint 规则来决定插入点;insertField会参考CodeStyleOptions;writeIndent([int level = 1])默认写两级空格缩进。

0.12.0 还加入了一套实验性 API:writeOverride2、writeReference2、writeType2、writeTypeParameter2、writeTypeParameters2,作为下一代成员写入接口的试验性前身。

5.3 DartFileEditBuilder 的破坏性变更(0.12.0 → 0.13.0)

  • 0.12.0:convertFunctionFromSyncToAsync与replaceTypeWithFuture发生破坏性变更。在源码中,这两个方法目前都需要FunctionBody/TypeAnnotation加TypeSystem、TypeProvider三个参数,用于在同步/异步函数间转换时同步调整返回类型(Future<T>)。另一个方向convertFunctionFromAsyncToSync与replaceTypeWithFutureArgument同样存在。二者对生成器函数(generator)体有限制,不满足条件时抛出ArgumentError。
  • 0.13.0:DartFileEditBuilder与DartEditBuilder再次发生破坏性变更(日志未列出细节,但可推断与写入 API 的重新设计相关)。
  • 0.14.0:移除各方法上已弃用的methodBeingCopied参数。

5.4 链接编辑(Linked Edit)与导入管理

EditBuilder.addLinkedEdit(groupName, builder)与addSimpleLinkedEdit支持把编辑中的文本区域归入链接编辑组,并附带LinkedEditSuggestionKind类型的建议值,供 IDE 实现"重命名一处、联动多处"的交互。FileEditBuilder.addLinkedPosition(range, groupName)则把既有代码区域纳入链接组。

导入管理集中在DartFileEditBuilder.importLibrary与importLibraryElement:

  • importLibrary(uri, {prefix, showName, useShow}):安排为给定 URI 的库添加 import;可指定前缀、show 子句;返回实际写入指令的 URI 文本(可能因 lint 规则从绝对 URI 转为相对 URI);
  • importLibraryElement:确保库已导入——若已存在且未带前缀,则修改现有 import 以展示showName;若已带前缀则新增一个无前缀 import;
  • importsLibrary(uri):查询某库是否已被现有或计划中的编辑导入;
  • fileHeadersetter:设置在生成的 import 之前的文件头(自动补一个空行);
  • requiredImports:列出编辑中引用的新类型所必须导入的 URI。

ImportPrefixGenerator类型在 change_builder_dart.dart 中已被标注@Deprecated('This type is no longer used or necessary'),呼应 0.14.0 移除importPrefixGenerator参数的变更。

六、RangeFactory 的两次改名(0.13.0 → 0.13.2 → 0.14.0)

RangeFactory是生成SourceRange的工厂类,range_factory.dart 提供了从 AST 节点、token、语法实体、offset 组合派生范围的大量方法,例如:

  • node(AstNode)、token(Token)、entity(SyntacticEntity):覆盖单个语法实体;
  • startEnd(left, right)、endEnd(left, right)、startStart、endStart:按两个实体的起止位置组合范围;
  • startLength、endLength、offsetBy:按偏移与长度构造;
  • argumentRange(argumentList, lower, upper, forDeletion):覆盖参数列表中的一段;forDeletion为true时包含邻近逗号以支持安全删除(对(a, b, c, d)取下标 1~2 时,范围分别是'b, c'或', b, c');
  • deletionRange(node, {overrideEnd}):考虑节点前后的空白与注释,计算可安全删除的范围;
  • nodeInList(list, item):返回列表中单个元素含前导/尾随逗号的范围。

该类的演进体现了 API 清理的连贯性:

  1. 0.13.0:移除elementName(),改用fragmentName()。fragmentName(Fragment fragment)基于 fragment 的nameOffset/name返回名称范围,对合成(synthetic)fragment 返回null。
  2. 0.13.2:弃用RangeFactory.error,由RangeFactory.diagnostic替代。diagnostic(Diagnostic)返回与诊断对象范围一致的SourceRange。
  3. 0.14.0:删除已弃用的RangeFactory.error方法。

这一系列变更显示:插件 API 越来越强调"诊断对象"与"元素片段(fragment)"这些新概念,逐步淘汰旧有的"错误(error)"与"元素名(elementName)"表述。

七、协议层演进:真枚举、AnalysisStatus 与 SourceEdit 变更描述

7.1 协议枚举转为真枚举(0.12.0)

0.12.0 是协议层最大的一次破坏性变更:lib/protocol/protocol_common.dart与lib/protocol/protocol_generated.dart中所有实现Enum的类全部转为真正的 Dart enum。影响如下:

  • 每个枚举不再有静态VALUES字段;
  • 无公开构造函数;
  • 枚举值不再有实例 gettername(但dart:core的EnumName扩展提供了name);
  • 枚举实例被视为穷尽(exhaustive),既有 switch 语句/表达式可能触发新的诊断。

这解释了 AnalyzerConverter 中大量使用.values.byName(...)的写法——例如convertErrorSeverity用plugin.AnalysisErrorSeverity.values.byName(severity.name)完成 analyzer 诊断严重级别到插件协议枚举的映射。

7.2 AnalysisStatus 通知(0.13.0)

0.13.0 支持插件发送AnalysisStatus通知,带有一个isAnalyzing布尔字段。这一字段让 IDE 能够获知插件当前是否处于分析中,用于展示加载状态。搜索仓库可知该字段贯穿 protocol_generated.dart 与集成测试的协议匹配器(protocol_matchers.dart)。

7.3 SourceEdit 变更描述(0.12.0)

0.12.0 支持在SourceEdit上附加变更描述(change descriptions),使编辑结果可携带人类可读的说明信息,IDE 可在应用编辑时展示。

八、混入(Mixin)与贡献者体系的演进

0.14.0 将AssistContributorMixin从普通类改为 mixin。当前实现位于 assist_contributor_mixin.dart:mixin AssistContributorMixin on AssistContributor,提供addAssist(AssistKind kind, ChangeBuilder builder, {List<Object>? args})工具方法——通过 kind 获取消息与优先级,通过 builder 获取编辑集;当编辑集为空时不产生 assist;否则设置change.id、change.message(用formatList填充消息参数)并交给collector以PrioritizedSourceChange形式收集。

插件的各类功能请求都通过**贡献者(contributor)**模式组装。例如 assist_mixin.dart 中的AssistsMixin提供handleEditGetAssists的通用实现:先由getAssistContributors(path)取得贡献者列表,再构造AssistRequest,交给AssistGenerator生成响应。配套的DartAssistsMixin则基于getResolvedUnitResult构造DartAssistRequestImpl。类似地,lib/plugin 目录下还有fix_mixin.dart、completion_mixin.dart、folding_mixin.dart、highlights_mixin.dart、navigation_mixin.dart、occurrences_mixin.dart、outline_mixin.dart等,对应导航、折叠、高亮、出现次数、大纲、补全、修复等能力,均在相应版本迭代中随协议演进。

九、早期版本里程碑:从 0.0.1 到 0.5.0

  • 0.0.1:初始版本。
  • 0.0.1-alpha.7:移除CompletionSuggestion.elementUri,改用AvailableSuggestionSet;从CompletionSuggestion移除importUri;补全建议中纳入类型参数。
  • 0.2.0:DartEditBuilder.writeOverride()改为接受ExecutableElement而非FunctionType(当前 writeOverride 的签名即ExecutableElement element)。
  • 0.2.3:新增Relevance类;FixKind.name改为FixKind.id(官方认定为良性破坏性变更,因原name仅用于调试);新增computeDartNavigation函数;注意此版本从未发布(存在对package:analysis_server的问题导入)。
  • 0.2.4:公开AnalyzerConverter.locationFromElement(原为私有)。
  • 0.3.0:移除已弃用的Plugin.getResolveResult,改用getResolvedUnitResult。
  • 0.5.0:稳定空安全发布,依赖更新到空安全版本;要求 SDK 2.14 以使用Object.hash();要求yaml 3.1.0以使用recover。此时 analyzer 支持范围改为^1.3.0。

0.8.0 的"Require SDK2.14to useObject.hash()"与yaml 3.1.0的recover依赖,表明该版本是空安全依赖链全面落地的收尾。

十、版本时间线总览

版本核心变更摘要
0.0.1 ~ 0.0.1-alpha.8初始发布,随 pkg:analyzer 演进
0.2.xwriteOverride 签名变更、Relevance 与 FixKind.id、AnalyzerConverter.locationFromElement 公开
0.3.0移除 getResolveResult,改用 getResolvedUnitResult
0.4.0引入 ChangeBuilder 替代 DartChangeBuilder
0.5.0稳定空安全;移除 DartChangeBuilder;overlay 机制重构
0.6.0协议 bug 修复
0.7.0 ~ 0.11.3analyzer 2.x~6.x 支持;0.11.0 起采用 AnalysisContextCollection/AnalysisContext 模型
0.12.0协议枚举转真枚举;DartEditBuilder/DartFileEditBuilder 新 API;SourceEdit 变更描述
0.13.0移除 elementName();DartFileEditBuilder/DartEditBuilder 破坏性变更;AnalyzerConverter 破坏性变更;AnalysisStatus 通知
0.13.2弃用 RangeFactory.error → diagnostic
0.14.0AssistContributorMixin 转 mixin;移除若干弃用 API 与参数
0.14.1 ~ 0.14.17analyzer 10.0.x~14.4.0 逐版本对齐
0.14.18-dev要求 analyzer 14.5.0-dev

十一、给插件开发者的升级指南

结合变更日志与源码,升级插件时可遵循以下要点:

  1. 版本配对升级:任何 analyzer_plugin 升级都必须同步升级 analyzer 到对应版本(见第二节对照表),二者不可错位。
  2. 优先处理破坏性变更版本:0.12.0(协议枚举)、0.13.0(RangeFactory 与编辑构建器)、0.14.0(移除弃用 API)是三个跳板版本,建议逐个跨越、分别编译验证。
  3. 统一使用新 API:
    • 构建变更一律使用ChangeBuilder的addDartFileEdit/addGenericFileEdit/addYamlFileEdit,不再使用旧式addFileEdit;
    • 获取范围统一使用RangeFactory.diagnostic与fragmentName,避免error与elementName;
    • 范围/位置转换使用AnalyzerConverter(analyzer_converter.dart)。
  4. 适配真枚举:协议枚举已无VALUES字段,switch 需保证穷尽性,name请通过EnumName扩展获取。
  5. 模型对齐:分析能力基于AnalysisContextCollection构建,覆盖handleAffectedFiles时记得先过滤contextRoot.isAnalyzed,避免分析范围外文件。
  6. 新项目改用 analysis_server_plugin:本包已标记 legacy,仅当维护既有插件或研究协议历史时使用本框架。

十二、可深入研读的仓库入口

  • 变更日志原文:pkg/analyzer_plugin/CHANGELOG.md
  • 包说明与使用指引:pkg/analyzer_plugin/README.md
  • 依赖与版本声明:pkg/analyzer_plugin/pubspec.yaml
  • 插件基类与请求分发:pkg/analyzer_plugin/lib/plugin/plugin.dart
  • 变更构建器核心:pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_core.dart
  • Dart 编辑构建器:pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
  • 范围工厂:pkg/analyzer_plugin/lib/utilities/range_factory.dart
  • 协议转换器:pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
  • 各类功能 mixin:pkg/analyzer_plugin/lib/plugin
  • 插件启动器:pkg/analyzer_plugin/lib/starter.dart
  • 编程语言
  • 编译器
  • 语言运行时
  • 标准库
  • 开发工具

【免费下载链接】sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.

项目地址:https://gitcode.com/gh_mirrors/sdk1/sdk
点击查看免费下载

相关推荐

上一篇:探索高效桌面:i3wm-themer——为你的终端带来无尽风格
下一篇:探秘JavaScript的内存管理神器:Mnemonist

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 2:13:27

毫米波雷达无线感知:DETR动作识别毕设源码详解

简介&#xff1a;基于毫米波雷达的无线感知智能化算法设计&#xff0c;完整毕业设计源码与论文文件打包为zip。面向智能家居应用场景&#xff0c;方案提出将特征队列提取与任务输出需求解耦的系统架构&#xff0c;利用人体骨架关键点、锚定框等通用中间特征统一不同任务&#x…

作者头像 李华
网站建设 2026/9/25 2:12:43

2026论文AI率检测成新标尺,Paperxie中文定稿与留学申请双场景实操指南

2026年&#xff0c;论文圈最热的话题早已不是重复率那几个百分点&#xff0c;而是“AI率”——也就是一篇文本被判定为AI生成的概率。我身边越来越多学生被导师叫去谈话&#xff0c;理由不是抄袭&#xff0c;而是“论文里疑似AI的味道太重”。更麻烦的是&#xff0c;同样一篇自…

作者头像 李华
网站建设 2026/9/25 2:11:00

【Dify】多阶段深度学习图像处理应用

深度学习驱动的多阶段图像处理工作流正在成为视觉内容生成与优化的重要工具。以模型节点协同方式,流程实现了图像的逐步增强和智能化处理,适合初学编程者理解与上手。 本文梳理了典型多模型工作流的操作流程,解析每个环节的节点作用与实现方式,展示多场景下的应用方法,为…

作者头像 李华
网站建设 2026/9/25 2:10:46

【Dify】Ubuntu云服务器部署Dify的两种方式

开源大语言模型应用开发平台Dify,为AI应用开发者带来了极高的便利,支持可视化创建聊天助手、RAG应用、Agent智能体与自动化工作流。本文整理了Dify在宝塔面板与原生Linux环境下的具体部署方式,兼顾不同用户的实际需求。 本文将介绍两种常见的Dify部署方法,包括在宝塔面板中…

作者头像 李华
网站建设 2026/9/25 2:10:15

Springboot 集成 Ehcache操作数据库显示SQL语句设置

Springboot 集成 Ehcache操作数据库显示SQL语句设置2023-09-13 23:33:35.030 INFO 6124 --- [ task-1] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2023-09-13 23:33:35.124 INFO 6124 --- [ t…

作者头像 李华