一文搞懂Kotlin符号处理接口KSP

news2024/11/30 14:31:54

公众号「稀有猿诉」        原文链接 一文搞懂Kotlin符号处理接口KSP

Kotlin符号处理(Kotlin Symbol Processing)即KSP是可以用于开发轻量级编译器插件的一套API。是Kotlin原生的,Kotlin语法友好的编译器插件。使用简单且易于上手,可以实现一些非常强大的编译时代码处理功能,如代码生成和代码检查。今天就来学习一下KSP的基本原理,以及如何使用KSP API。

注意,本文是Kotlin中较为高级的话题,适合有一定的Kotlin基础的同学,否则理解起来可能有难度,可以事先阅读前面的文章。

什么是KSP

与前文提到的注解处理器kapt类似,KSP也是一种编译时的插件,能够在编译前处理Kotlin语言的符号。KSP API能地道地处理Kotlin的源码,因为它是专门为Kotlin而设计的,能够完全的理解和识别Kotlin的语言符号,以及Kotlin专属的特性:如扩展函数,声明点泛型变化以及本地函数。KSP API基于Kotlin的语法,把Kotlin程序拆解为各种静态的符号,可以处理如类,成员,函数,参数 以及注解等等。但它并不是运行时的(那是反射做的事情),因此像逻辑如循环和条件语句是没有办法进行处理,以及也无法得到表达式的结果。

虽然KSP是编译器插件,但它是运行在最终编译之前,也就是说在编译器编译全部代码之前,事先会运行KSP插件。所以KSP API最适合做的事情是:

  1. 读取代码和各种资源文件,并进行分析
  2. 生成代码

接下来看如何具体使用KSP API。

配置KSP

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

KSP是由谷歌开发的一套工具,包括两部分一个是Kotlin plugin,另一个是依赖库。所以需要在项目的根build.gradle里面,先把plugin添加到项目里:

// The root build.gradle of your project
plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.9.23' apply false
    id 'com.google.devtools.ksp' version '1.9.23-1.0.20' apply false
}

当然,这一步其实并不是必须的,也可以在每个模块中再配置plugin。

接下来,在使用KSP的模块里面添加plugin,添加依赖以及指明KSP processor,这是最为关键的配置:

// module build.gradle
plugins {
    id 'org.jetbrains.kotlin.jvm'
    id 'com.google.devtools.ksp'
}

dependencies {
    implementation project(':kspannotation')
    ksp project(':kspprocessor')
}

如果项目顶层指定了plugin的版本,那么到了module这里,就不必再指定版本了。另外就是要注意版本的匹配,ksp的版本前半段『1.9.23』指明 的是最低的Kotlin版本要求。最好是让ksp要求的版本与指定的Kotlin版本匹配或者差距较小,否则可能会有问题。dependencies中的ksp指定的是KSP processor,对于有些库可能注解和定义和KSP的processor可能会在同一个包里,那么写一句就够了,如Room的,就一句:ksp ‘androidx.room:room-compiler:2.6.1’。

如果是自定义的processor,需要为processor单独建一个library module,配置ksp库为依赖即可:

// KSP processor module build.gradle
plugins {
    id 'org.jetbrains.kotlin.jvm'
}

dependencies {
    implementation project(':kspannotation')

    implementation 'com.google.devtools.ksp:symbol-processing-api:1.9.23-1.0.20'
    implementation 'com.squareup:kotlinpoet-ksp:1.16.0'
}

典型的KSP procesor(包括网上大部分的例子)都是分了三个module,一个是定义注解的module,一个是实现processor的,一个是使用注解和processor的。但这并不是必须的,为了方便,其实把注解的定义和processor放在一个module就可以了。只要把processor与使用它的module分开来了,就可以。

**注意:**对于processor module来说它的类型要是library,并且要是Java library或者Kotlin library,因为这是Kotlin语言层面的东西。对于Android同学来说在新建module时一定要选择『Java or Kotlin Library』。

实现KSP Processor

配置好了模块后,剩下的就是要实现一个KSP processor了。

实现Processor

大部分工作plugin已经做好了,我们需要做的就是实现一些接口。有两个需要实现,一个是SymbolProcessorProvider,另一个则是SymbolProcessor。

SymbolProcessorProvider相当于是processor的一个工厂方法,我们实现它的create方法,返回一个SymbolProcessor实例,一个典型的实现:

class MyProcessorProvider : SymbolProcessorProvider {
    override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
        return MyProcessor(environment.codeGenerator)
    }
}

它就相当于一个工厂方法,把上下文环境传给processor,SymbolProcessor是重点,我们需要实现它的process方法,针对感兴趣的符号进行处理,比如用KotlinPoet生成代码,这里是发挥创造力的地方:

class MyProcessor(private val generator: CodeGenerator) : SymbolProcessor {
    override fun process(resolver: Resolver): List<KSAnnotated> {
        val annotatedClasses = resolver
            .getSymbolsWithAnnotation(MyAnnotation::class.java.name)
            .filterIsInstance<KSClassDeclaration>()

        for (aclass in annotatedClasses) {
            val packageName = aclass.packageName.asString()
            val className = aclass.simpleName.asString()
            val methods = aclass.getDeclaredFunctions())
            // ...
         }
        return emptyList()
    }
}

注册Processor

实现了process后还需要把process注册一下,否则ksp plugin无法找到这个processor。在processor module与代码同级文件夹下新建文件『resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider』,然后把刚才实现的provider的完整类名,写在文件里,如果是使用IDE一般都会有提示的。

// myprocessor/src/main/
//    |-- kotlin/net/toughcoder/
//              |-- MyProcessorProvider.kt
//              |-- MyProcessor.kt
//    |-- resources/META-INF/services/
//              |-- com.google.devtools.ksp.processing.SymbolProcessorProvider
// file: resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
net.toughcoder.MyProcessorProvider

为啥要用KSP

目前来说KSP最主要应用仍然 是注解的处理,以及配合注解进行代码生成。通过前面一篇关于注解的文章中我们知道,注解的处理已经有了一个专门的工具了叫做kapt,就目前来说KSP能做的事情kapt也都能做,它们都是用于编译时代码处理以及代码生成,都能处理注解。那么,在已经有了kapt的前提下,为啥还要搞KSP呢?

kapt虽然是Kotlin的注解处理器,但是它保持Java的兼容性,它直接复用了Java的AbstractProcessor,要依赖于Java的annotation procssor以及javac,只适用于Kotlin/JVM,其他target用不起来,因此它并不能算是Kotlin原生的工具,对Kotlin的特性支持不友好。再有就是,为了保持与javac的兼容性,它的处理速度很慢,必须先把Kotlin代码转成javac能认识的标准Java代码,这肯定会有不必要的性能开销。基于这些限制,kapt已经停止开发了,处于维护状态了,不会再添加新功能了。省流点来说,kapt是以Java角度来看待输入代码的(即也要处理的源码),而KSP是以Kotlin角度

KSP则是Kotlin原生的,基于Kotlin开发的,且是为了Kotlin开发的,并不受限于javac,因此所有的Kotlin目标平台都能用。并且对Kotlin的特性支持的很友好。它的处理速度也较kapt有提升,因为不必要做编码转换了,省了一道工序。从官方给出的数据看至少能省25%的编译时间。另外,KSP的API使用起来更加的Kotlin友好一些SymbolProcessor传递过来的Resolver有很方便的接口可以取得被标的类,而且符号对象是KSClassDeclaration,它可以方便的取一个Kotlin类的相关的其他符号,如包名,类名,方法等。

总结

通过本文我们理解了KSP的概念,并学会了如何在项目中配置KSP, 以及如何实现一个KSP processor。KSP视Kotlin代码为一系列的静态符号,对Kotlin语言特性支持友好,处于活跃的开发状态且被官方大力支持,因此应该尽早转向KSP。并且相信KSP能做的事情会越来越多。

参考资料

  • Kotlin Symbol Processing API
  • Migrate from kapt to KSP
  • Write a Symbol Processor with Kotlin Symbol Processing
  • An Introduction to Kotlin Symbol Processing
  • Kotlin Symbol Processing

欢迎搜索并关注 公众号「稀有猿诉」 获取更多的优质文章!

原创不易,「打赏」「点赞」「在看」「收藏」「分享」 总要有一个吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1602803.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

同城货运系统的开发与货运搬家软件的技术性探讨和市场分析

一、市场前景展望 随着城市化进程的加快和电商物流的蓬勃发展&#xff0c;同城货运市场展现出了巨大的潜力。尤其是在快节奏的生活环境中&#xff0c;个人和企业对于快速、便捷、可靠的货运搬家服务需求日益增长。同城货运系统与货运搬家软件作为连接货主与货运司机的桥梁&…

2024还想走c++后端的同学,该如何准备才有机会成功上岸拿到offer

c后端&#xff0c;一个被网上说没有市场的c方向。但是对于想从事c后端的同学该如何准备呢&#xff1f; 就目前的市场需求来说&#xff0c;c后端的需求市真不大&#xff0c;中小厂基本没有&#xff0c;大部分集中在大厂。 那么&#xff0c;如果大家想求职c后端&#xff0c;第一…

野生动物保护视频AI智能监管方案,撑起智能保护伞,守护野生动物

一、背景 在当今世界&#xff0c;野生动物保护已经成为全球性的重要议题。然而&#xff0c;由于野生动物生存环境的不断恶化以及非法狩猎等活动的盛行&#xff0c;保护野生动物变得尤为迫切。为了更有效地保护野生动物&#xff0c;利用视频智能监管技术成为一种可行的方案。 …

docker方式 部署jenkins服务,实现持续集成(CI/CD)功能

一、背景&#xff1a; 因公司需求&#xff0c;需要部署一套jenkins自动化部署服务&#xff0c;并且是通过docker容器的方式部署的。 二、jenkins简介&#xff1a; 什么是Jenkins &#xff1f; Jenkins是一个开源软件&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用…

VS集成vcpkg

VS集成vcpkg 下载vcpkg 下载vcpkg git clone https://github.com/Microsoft/vcpkg.git安装vcpgk&#xff0c;文件目录 .\bootstrap-vcpkg.bat集成到vs2022中 # 集成到项目 vcpkg integrate project vcpkg integrate installPS C:\Users\Administrator> vcpkg integrate…

Python入门教程完整版(懂中文就能学会)

网友虐我千百遍&#xff0c;我待网友如初恋&#xff0c;因为今天又给大家带来了干货&#xff0c;Python入门教程完整版&#xff0c;完整版啊&#xff01;完整版&#xff01; 为了吸取教训&#xff0c;小编一定要分享一下攻略&#xff0c;“怎样获得小编分享的教程呢&#xff1…

多线程同步:使用 std::mutex 和 std::unique_lock 保护共享资源

在当今的软件开发中&#xff0c;多线程编程是一项至关重要的技术&#xff0c;它允许程序同时执行多个任务&#xff0c;从而提高应用程序的效率和响应速度。然而&#xff0c;多线程环境也带来了数据安全和一致性的挑战。在多个线程需要访问和修改同一数据资源的情况下&#xff0…

【SAP NWDI】创建DC(Development component)(三)

一、准备DC组件包 首先需要下载下面这7个sca 的组件包,找到对应的ME版本的组件包,可以找对应的Basis帮忙下载。然后把这7个组件包放入到服务器中根目录的这个目录中,如果目录没有的需要自己创建出来。 二、导入DC组件包 注意:下面的的图中 有需要填写 in 和 out 的连个目…

RabbitMQ-核心特性

已经不需要为RabbitMQ交换机的离去而感到伤心了&#xff0c;接下来登场的是RabbitMQ-核心特性!!! 文章目录 核心特性消息过期机制消息确认机制死信队列 核心特性 消息过期机制 官方文档&#xff1a;https://www.rabbitmq.com/ttl.html 可以给每条消息指定一个有效期&#xf…

富文本在线编辑器 - tinymce

tinymce 项目是一个比较好的富文本编辑器. 这里有个小demo, 下载下来尝试一下, 需要配置个本地服务器才能够访问, 我这里使用的nginx, 下面是我的整个操作过程: git clone gitgitee.com:chick1993/layui-tinymce.git cd layui-tinymcewget http://nginx.org/download/nginx-1.…

监控系统泛滥:CTO 面临的隐形成本危机

在信息技术飞速发展的今天&#xff0c;构建和维护现代化的数字系统变得日益复杂和关键&#xff1b;在这样的背景下&#xff0c;监控系统的作用变得尤为突出。正如业界广泛流传的一句经验之谈“无监控&#xff0c;不运维”所揭示的道理一样&#xff0c;对于任何具有一定复杂性的…

Redis(Windows版本下载安装和使用)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

lua 光速入门

文章目录 安装注释字符串变量逻辑运算条件判断循环函数Table (表)常用全局函数模块化 首先明确 lua 和 js Python一样是动态解释性语言&#xff0c;需要解释器执行。并且不同于 Python 的强类型与 js 的弱类型&#xff0c;它有点居中&#xff0c;倾向于强类型。 安装 下载解释…

AI预测福彩3D第38弹【2024年4月17日预测--第8套算法开始计算第6次测试】

今天咱们继续测试第8套算法和模型&#xff0c;今天是第5次测试&#xff0c;目前的测试只是为了记录和验证&#xff0c;为后续的模型修改和参数调整做铺垫&#xff0c;所以暂时不建议大家盲目跟买~废话不多说了&#xff0c;直接上结果&#xff01; 2024年4月17日3D的七码预测结果…

vivado 与 VIO 核输出探针进行交互

与 VIO 核输出探针进行交互 VIO 核输出探针用于将值写入实际硬件中的 FPGA 或 ACAP 中运行的设计。 VIO 输出探针通常用作为待测设计的低带 宽控制信号。 VIO 调试探针需手动添加到 VIO 仪表板的“ VIO 探针 (VIO Probes) ”窗口中。请参阅“在‘调试探针 (Debug Pr…

中国12.5米DEM地形瓦片数据免费领取!

之前向大家公开了中国34个省12.5米DEM地形瓦片数据的免费领取链接&#xff0c;大家对12.5米DEM数据的使用需求很强烈&#xff0c;领取也很积极&#xff0c;也有不少读者反馈能否提供全国范围的12.5米DEM地形瓦片数据&#xff0c;因为分省级地形瓦片数据想要合并成全国数据&…

CUDA 以及MPI并行矩阵乘连接服务器运算vscode配置

一、CUDA Vscode配置 &#xff08;一&#xff09;扩展安装 本地安装 服务器端安装 &#xff08;二&#xff09; CUDA 配置 .vscode c_cpp_properties.json {"configurations": [{"name": "Linux","includePath": ["${workspa…

【AI】DeepStream(01)介绍

1、简介 DeepStream 本质是 GStreamer 的插件,基于GStreamer的管道,实现高效的视频流分析。 DeepStream 将来自 USB/CSI 摄像头的流数据、来自文件的视频或通过 RTSP 的流作为输入,并使用人工智能和计算机视觉从像素中生成AI结果。 DeepStream SDK 可以成为许多视频分析解…

C++ queue priority_queuestack 详解及模拟实现

1. stack的介绍和使用 1.1 stack的介绍 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。 2. stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其底层的容…

【华为笔试题汇总】2024-04-17-华为春招笔试题-三语言题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是KK爱Coding &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为近期的春秋招笔试题汇总&#xff5e; &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f…