当前位置: 首页 > news >正文

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)模式:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。

访问者模式包含的核心类包括:

  1. 抽象访问者(Visitor):定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
  2. 具体访问者(ConcreteVisitor):实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
  3. 抽象元素(Element):声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
  4. 具体元素(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,并交由子类具体实现:

  1. isAcceptable:用于判断是否可以接受访问器参数的访问
  2. 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. 配方&#xff08;Recipe&#xff09;执行流程 …...

LeetCode_Java_递归系列(题目+思路+代码)

206.反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]以此类推&#xff0c;直到反转结束返回头结点 class Solution {public ListNode rever…...

c++ 编译为WebAssembly时,怎么判断是release/debug环境?

我对这块研究不深 我的需求是把cpp代码编译为wasm的形式时&#xff0c;需要知道是debug/release 然而 尝试了一些办法 没有满足我的需求 尝试1&#xff1a; #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手机接入过程&#xff0c;手机附着过程 附着&#xff08;Attach&#xff09;&#xff1a; 终端在PLMN中注册&#xff0c;从而建立自己的档案&#xff0c;即终端上下文 进行附着的三种情况&#xff1a; ①终端开机后的附着&#xff0c;初始附着 ②终端从覆盖盲区返回到…...

【LeetCode-46.全排列】

题目详情&#xff1a; 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2&#xff1a; …...

【Web】浅聊Jackson序列化getter的利用——POJONode

目录 核心速览 原理分析 EXP TemplatesImpl利用 SignedObject利用 核心速览 writeValueAsString是jackson序列化自带的入口&#xff0c;在调用该方法的过程中将会通过遍历的方法将bean对象中的所有的属性的getter方法进行调用 下面介绍如下利用链&#xff1a; BadAttrib…...

osgEarth学习笔记2-第一个Osg QT程序

原文链接 上个帖子介绍了osgEarth开发环境的安装。本帖介绍我的第一个Osg QT程序。 下载 https://github.com/openscenegraph/osgQt 解压&#xff0c;建立build目录。 使用Cmake-GUI Configure 根据需要选择win32或者x64&#xff0c;这里我使用win32. 可以看到include和lib路…...

2024年发布jar到国外maven中央仓库最新教程

2024年发布jar到国外maven中央仓库最新教程 文章目录 1.国外sonatype仓库的版本1.1老OSSHR账号注册说明1.2新账号注册说明 2.新账号注册(必选)3.新账号登录创建Namespace3.1创建Namespace的名字的格式要求&#xff08;必选&#xff09;3.2发布一个静态网站&#xff08;可选&…...

在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 置顶窗口崩溃无法退出解决,停止运行快捷键设置

有时置顶窗口调试崩溃需要快捷键进行关闭&#xff0c;如下设置即可 这样就可以通过全局快捷键退出了&#xff0c;避免置顶崩溃无法关闭程序的问题。...

HBCalculator 程序:通过 VMD 可计算分子动力学模拟中氢键密度和强度的一维和二维分布

分享一个通过 VMD 可计算分子动力学模拟中氢键密度和强度的一维和二维分布程序 HBCalculator。 感谢论文的原作者&#xff01; 主要内容 “氢键是分子系统中关键的非共价相互作用&#xff0c;对生物、化学和能量相关过程产生重大影响&#xff1b;因此&#xff0c;描述氢键信息…...

鸿蒙-项目创建及了解

目录 项目创建 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类(九)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;六&#xff09; 下一篇&#xff1a; 无 33、sqlite3_column_table_name 函数 sqlite3_column_table_name 用于返回结果集中指定列所属的表的名称。如果查询中列使…...

idea2023 运行多 springboot 实例

概要 1、修改idea运行多实例&#xff08;本地测试负载&#xff09; 你可能用到其他 1、改造项目缓存token 至redis 支持负载均衡部署 SpringSecurity6.0RedisJWTMP基于token认证功能开发&#xff08;源码级剖析可用于实际生产项目&#xff09;_springsecurity redis管理token…...

HarmonyOS系统开发ArkTS常用组件编程技巧

目录 样式复用 Styles方法 Extend方法 组件编程在使用过程中有很多技巧&#xff0c;在这里分享样式复用技巧和UI结构复用技巧。 样式复用 我们观察下面的代码&#xff0c;在代码中很多重复行的代码&#xff0c;如&#xff1a; Image 的 .width(30).height(30) 是重复的But…...

大数据开发(Hive面试真题-卷三)

大数据开发&#xff08;Hive面试真题&#xff09; 1、Hive的文件存储格式都有哪些&#xff1f;2、Hive的count的用法&#xff1f;3、Hive得union和unionall的区别&#xff1f;4、Hive的join操作原理&#xff0c;left join、right join、inner join、outer join的异同&#xff1…...

Oracle数据库SQL开发规范

Oracle数据库SQL开发规范是为了保证SQL代码的质量、可读性和性能而遵循的一系列准则和最佳实践。以下是一些常见的Oracle SQL开发规范要点&#xff1a; 1. 命名规范 使用有意义且一致的命名约定&#xff0c;例如表名采用TBL_MODULE_NAME&#xff0c;视图采用VW_MODULE_VIEW等…...

FreeRTOS 消息队列

1. 队列简介 1.1 队列的概念 队列是任务到任务、任务到中断、中断到任务数据交流的一种机制&#xff08;消息传递&#xff09; 类似全局变量&#xff1f;假设有一个全局变量a 0&#xff0c;现有两个任务都在写这个变量 a&#xff1a; 大家想象一下如果任务 1 运行一次&#…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...