OpenRewrite框架原理解析
目录
1. OpenRewrite处理流程概述
2. OpenRewrite访问者模式的应用
2.1 访问者模式简介
2.2 OpenRewrite框架如何应用访问者模式
2.2.1 抽象访问者&具体访问者
2.2.2 抽象元素&具体元素
3. LST无损语义树构造
4. 配方(Recipe)执行流程
4.1 执行入口
4.2 LargeSourceSet说明
4.3 配方执行时序图
4.4 配方执行结果表示
OpenRewrite通过将不同类型的源文件构建为Lossless Semantic Trees (LST)无损语义树的数据结构,能够准确和全面地表示源文件的元数据和语义信息。构造完LST后,通过应用访问者模式,将LST数据结构本身与访问LST元素的操作解耦,使得我们能够灵活的自定义各种访问操作,而又不改变LST数据结构。
本文主要对OpenRewrite框架设计和原理进行解析,分析OpenRewrite框架中是如何运用访问者模式进行架构设计的,然后进一步分析访问逻辑的具体执行过程,以便更清楚的掌握OpenRewrite内部执行机理,拨开云雾见月明,进而更好的指导OpenRewrite开发实践。
关于OpenRewrite的介绍和Recipe简单开发实践请参考前述文章:
大规模自动化重构框架--OpenRewrite浅析
OpenRewrite:实现一个简单的配方(Recipe)
1. OpenRewrite处理流程概述
OpenRewrite作为自动化重构的框架,其内部处理流程是通过配方(Recipe)来触发执行的,顶层处理流程如下:

- Recipe:允许使用者自定义重构逻辑的封装类,内部通过getVisitor方法返回构造好的访问器,进而执行访问器的重构规则
- Tree:作为LST(无损语义树)的顶层抽象元素,是所有文件类型中元素的顶层接口类
- SourceFile:所有不同类型文件解析后顶层具体元素的父接口,比如Java源文件解析为J.CompilationUnit是SourceFile的具体实现子类
- LargeSourceSet:需要改写的源文件集合的封装类,内部可以包含不同文件类型的源文件
- TreeVisitor:顶层访问器接口,针对不同的文件类型,派生了不同的子类访问器接口,比如针对Java语言,定义了JavaVisitor
- Changeset/Result:源文件集合(LargeSourceSet)经过配方(Recipe)中的访问器(TreeVisitor)访问后的结果集,包含了重构前(before)和重构后(after)的表示
2. OpenRewrite访问者模式的应用
2.1 访问者模式简介
在具体说明OpenRewrite框架中访问者模式是如何应用的之前,先简单回顾下访问者模式的基本要素:
访问者(Visitor)模式:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。
访问者模式包含的核心类包括:
- 抽象访问者(Visitor):定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
- 具体访问者(ConcreteVisitor):实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
- 抽象元素(Element):声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
- 具体元素(ConcreteElement):实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作
2.2 OpenRewrite框架如何应用访问者模式
在介绍完访问者模式的基本概念后,下面说明下访问者模式在OpenRewrite框架中是如何运用的。
2.2.1 抽象访问者&具体访问者
在OpenRewrite中,抽象访问者为抽象基类TreeVisitor,并且针对不同类型的访问对象,定义了不同类型的访问器,各访问器的整体类图继承结构如下:

- JavaVisitor:针对Java源代码文件的访问器,支持访问Java源代码中的各种元素,比如:包名(Package)、类声明(ClassDeclaration)、方法声明(MethodDeclaration)、变量声明(VariableDeclarations)等
- PropertiesVisitor:针对Properties属性文件的访问器,支持访问属性文件中的键值对、注释等元素
- YamlVisitor:和PropertiesVisitor访问器类似,支持对yaml类型文件的访问
- XmlVisitor:针对Xml类型文件的访问器,支持访问Xml文件的各种元素,包括Tag、属性Attribute等
- MavenVisitor:针对Maven Pom文件的访问器,由于Pom文件也属于Xml格式文件,所以这里MavenVisitor继承了XmlVisitor
- JsonVisitor:针对Json格式文件的访问,比如元素JsonKey、JsonValue等
除此之外,OpenRewrite还提供了针对上述不同类型访问器的XXXIsoVisitor版本的访问器,区别之处是Iso版本的各个visit方法返回的是被访问元素本身,如果访问逻辑不改变被访问元素类型,使用Iso版本可以规避手动类型转换的工作,对使用者更友好。
在如上各种类型的访问器中:
- 通过isAcceptable方法判断该访问器是否可以应用到被访问元素上
- 通过各种visit方法实现不同类型元素的访问
2.2.2 抽象元素&具体元素
在OpenRewrite框架中,顶层抽象元素是接口Tree,并且针对不同的文件类型,扩展了不同的顶层抽象元素,其整体类图如下:

- J:Java项目的顶层抽象元素接口,其子类包括J.CompilationUnit、J.ClassDeclaration、J.Package等具体Java元素
- Properties:Properties属性文件中元素的顶层抽象元素,子类包括具体元素:键值对(Properties.Entry)等
- Xml:Xml文件中元素的顶层抽象元素,子类包含了具体元素:声明(XmlDecl)、Tag等
- Yaml:yaml文件中元素的顶层抽象元素,子类包括:Document、Entry等
- Json:Json格式文件中元素的顶层抽象元素,子类包括具体元素:Member、JsonObject、Array等
在顶层元素Tree中,定义了抽象方法isAcceptable和accept,并交由子类具体实现:
- isAcceptable:用于判断是否可以接受访问器参数的访问
- accept:接受访问器参数的访问,执行访问器中的具体访问逻辑
针对Java语言,这里图示下各种具体元素的类图,如下:

3. LST无损语义树构造
OpenRewrite自动化重构主要涉及2个流程:
1)将源文件解析为LST的过程,根据不同的源文件类型,调用对应的Parser解析器类构造差异化的各种元素
2)LST构造完成后,调用配方(Recipe)中的访问器执行自动化代码重构
不同类型源文件对应的Parser解析器类图如下:

JavaParser:针对Java源文件代码的解析器顶层抽象接口,具体实现子类是针对不同JDK版本的解析器(解析器隔离,解析不同JDK版本的语法特性),比如Java8Parser解析JDK8版本,内部实现委托给ReloadableJava8Parser进行解析,最终将Java源代码文件解析为J.CompilationUnit顶层元素
PropertiesParser:针对Properties属性文件的解析器类,最终解析为Properties.File顶层元素
XmlParser:针对Xml类型文件的解析器类,最终解析为Xml.Document顶层元素
......其它类似
4. 配方(Recipe)执行流程
4.1 执行入口
配方的实际执行入口是:RecipeRun run(LargeSourceSet before, ExecutionContext ctx, int maxCycles, int minCycles)
- LargeSourceSet:表示输入源文件集合封装类,包含配方执行重构的文件列表
- ExecutionContext:配方执行上下文,可以用于全局参数传递等用途
- maxCycles:指定配方最大执行周期次数
- minCycles:指定配方最小执行周期次数
- RecipeRun:封装了配方执行后的结果,内部包含了结果集Changeset
4.2 LargeSourceSet说明
这里展开LargeSourceSet的类图如下,可以看出其内部包含了List<SourceFile>源文件集合:

4.3 配方执行时序图
配方(Recipe)执行过程的时序图细化如下:

其中,RecipeScheduler封装了配方调度执行的具体细节,内部会委托给RecipeRunCycle(配方单次执行的封装对象,最大执行次数可在调度时进行指定)执行实际的源文件改写;
RecipeRunCycle封装了配方单次执行的主体逻辑,其中主要包含了以下3个方法:
1)scanSources
对源文件集合进行前置扫描,通常用于在源文件实际改写前通过扫描源文件集合获取一些上下文信息,用于重构逻辑中辅助判断或者元数据获取
2)generateSources
用于在源文件实际改写前,生成新的源文件,并添加到源文件集合中进而执行后续的文件改写操作
3)editSources
执行实际的源文件改写操作,这里会调用配方(Recipe)中定义的访问器对源文件各具体元素进行visit,执行重构逻辑,该部分也是开发者可以覆写重构逻辑的地方
4.4 配方执行结果表示
配方执行完成后的结果存放到了RecipeRun类中,其中字段changeSet存放了所有变更的结果集List<Result>,对象Result中又保存了变更前(before)和变更后(after)的源文件

最终将重构后(after)的源文件进行输出,完成了自动化重构的处理流程。
相关文章:
OpenRewrite框架原理解析
目录 1. OpenRewrite处理流程概述 2. OpenRewrite访问者模式的应用 2.1 访问者模式简介 2.2 OpenRewrite框架如何应用访问者模式 2.2.1 抽象访问者&具体访问者 2.2.2 抽象元素&具体元素 3. LST无损语义树构造 4. 配方(Recipe)执行流程 …...
LeetCode_Java_递归系列(题目+思路+代码)
206.反转链表 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1]以此类推,直到反转结束返回头结点 class Solution {public ListNode rever…...
c++ 编译为WebAssembly时,怎么判断是release/debug环境?
我对这块研究不深 我的需求是把cpp代码编译为wasm的形式时,需要知道是debug/release 然而 尝试了一些办法 没有满足我的需求 尝试1: #include <iostream>bool isDebugMode() { #ifdef EMSCRIPTENbool isDebug EM_ASM_INT({return (typeof conso…...
信号处理--基于正则化聚合的共空间模态(CSP)脑电信号分类
目录 理论 工具 方法实现 代码获取 参考文献 理论 传统的通用空间模式 (CSP) 是一种流行的算法,用于对脑电图 (EEG) 信号进行分类。本文主要介绍小样本设置 (SSS) 中 CSP 的正则化和聚合技术。传统的 CSP 基于样本协方差矩阵估计。如果训练样本数量较少,其脑电图分类的…...
【2024年5月备考新增】《软考真题分章练习(含答案解析) - 11 项目风险管理(高项)》
1 题目 1、风险可以从不同角度、根据不同的标准来进行分类。百年不遇的暴雨属于()。 A.不可预测风险 B.可预测风险 C.已知风险 D.技术风险 2、人们对风险事件都有一定的承受能力,当()时,人们愿意承担的风险越大。 A.项目活动投入的越多 B.项目的收益越大 C.个人、组织拥…...
【3GPP】【核心网】【4G】4G手机接入过程,手机附着过程(超详细)
1. 4G手机接入过程,手机附着过程 附着(Attach): 终端在PLMN中注册,从而建立自己的档案,即终端上下文 进行附着的三种情况: ①终端开机后的附着,初始附着 ②终端从覆盖盲区返回到…...
【LeetCode-46.全排列】
题目详情: 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1: 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2: …...
【Web】浅聊Jackson序列化getter的利用——POJONode
目录 核心速览 原理分析 EXP TemplatesImpl利用 SignedObject利用 核心速览 writeValueAsString是jackson序列化自带的入口,在调用该方法的过程中将会通过遍历的方法将bean对象中的所有的属性的getter方法进行调用 下面介绍如下利用链: BadAttrib…...
osgEarth学习笔记2-第一个Osg QT程序
原文链接 上个帖子介绍了osgEarth开发环境的安装。本帖介绍我的第一个Osg QT程序。 下载 https://github.com/openscenegraph/osgQt 解压,建立build目录。 使用Cmake-GUI Configure 根据需要选择win32或者x64,这里我使用win32. 可以看到include和lib路…...
2024年发布jar到国外maven中央仓库最新教程
2024年发布jar到国外maven中央仓库最新教程 文章目录 1.国外sonatype仓库的版本1.1老OSSHR账号注册说明1.2新账号注册说明 2.新账号注册(必选)3.新账号登录创建Namespace3.1创建Namespace的名字的格式要求(必选)3.2发布一个静态网站(可选&…...
在ubuntu22.04.4安装freeswitch1.10.10
一、环境 No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.4 LTS Release: 22.04.4 Codename: jammy 二、依赖 1、 工具包 apt install -y openssh-server …...
qt 置顶窗口崩溃无法退出解决,停止运行快捷键设置
有时置顶窗口调试崩溃需要快捷键进行关闭,如下设置即可 这样就可以通过全局快捷键退出了,避免置顶崩溃无法关闭程序的问题。...
HBCalculator 程序:通过 VMD 可计算分子动力学模拟中氢键密度和强度的一维和二维分布
分享一个通过 VMD 可计算分子动力学模拟中氢键密度和强度的一维和二维分布程序 HBCalculator。 感谢论文的原作者! 主要内容 “氢键是分子系统中关键的非共价相互作用,对生物、化学和能量相关过程产生重大影响;因此,描述氢键信息…...
鸿蒙-项目创建及了解
目录 项目创建 1.App普通项目创建 2.元服务创建 项目结构 .hvigor .idea AppScope entry EntryAbility.ts pages resources module.json5 ohosTest hvigorfile.ts build-profile.json5 oh_modules build-profile.json5 hvigorfile.ts 项目运行 项目创建 F…...
SQLiteC/C++接口详细介绍sqlite3_stmt类(九)
返回:SQLite—系列文章目录 上一篇:SQLiteC/C接口详细介绍sqlite3_stmt类(六) 下一篇: 无 33、sqlite3_column_table_name 函数 sqlite3_column_table_name 用于返回结果集中指定列所属的表的名称。如果查询中列使…...
idea2023 运行多 springboot 实例
概要 1、修改idea运行多实例(本地测试负载) 你可能用到其他 1、改造项目缓存token 至redis 支持负载均衡部署 SpringSecurity6.0RedisJWTMP基于token认证功能开发(源码级剖析可用于实际生产项目)_springsecurity redis管理token…...
HarmonyOS系统开发ArkTS常用组件编程技巧
目录 样式复用 Styles方法 Extend方法 组件编程在使用过程中有很多技巧,在这里分享样式复用技巧和UI结构复用技巧。 样式复用 我们观察下面的代码,在代码中很多重复行的代码,如: Image 的 .width(30).height(30) 是重复的But…...
大数据开发(Hive面试真题-卷三)
大数据开发(Hive面试真题) 1、Hive的文件存储格式都有哪些?2、Hive的count的用法?3、Hive得union和unionall的区别?4、Hive的join操作原理,left join、right join、inner join、outer join的异同࿱…...
Oracle数据库SQL开发规范
Oracle数据库SQL开发规范是为了保证SQL代码的质量、可读性和性能而遵循的一系列准则和最佳实践。以下是一些常见的Oracle SQL开发规范要点: 1. 命名规范 使用有意义且一致的命名约定,例如表名采用TBL_MODULE_NAME,视图采用VW_MODULE_VIEW等…...
FreeRTOS 消息队列
1. 队列简介 1.1 队列的概念 队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递) 类似全局变量?假设有一个全局变量a 0,现有两个任务都在写这个变量 a: 大家想象一下如果任务 1 运行一次&#…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
