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

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

在这里插入图片描述

什么是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

Kotlin作为一种现代的、静态类型的编程语言,拥有诸多独特且强大的特性,虽然Kotlin语法简洁,但是想要深入理解他的新特性,熟练的使用在工作上面还是得要花费很大的时间成本来学习,因此我给大家准备了Kotlin从入门到精通高级Kotlin强化实战两份资料来帮助大家系统的学习Kotlin,需要的朋友扫描下方二维码,免费领取!!!

Kotlin从入门到精通

准备开始

  • 基本语法
  • 习惯用语
  • 编码风格在这里插入图片描述

基础

  • 基本类型
  • 控制流
  • 返回与跳转在这里插入图片描述

类和对象

  • 类和继承
  • 属性和字段
  • 接口
  • 可见性修饰词
  • 扩展
  • 数据对象
  • 在这里插入图片描述

函数和lambda表达式

  • 函数
  • 高级函数和lambda表达式
  • 内联函数在这里插入图片描述

其他

  • 多重申明
  • Ranges
  • 类型检查和自动转换
  • This表达式
  • 等式
  • 运算符重载
  • 在这里插入图片描述

互用性

  • 动态类型

工具

  • Kotlin代码文档
  • 使用Maven
  • 使用Ant
  • 使用Griffon
  • 使用Gradle在这里插入图片描述

FAQ

  • 与Java对比
  • 与Scala对比在这里插入图片描述

高级Kotlin强化实战

第一章 Kotlin入门教程

  • 1.Kotlin概述
  • 2.Kotlin与Java比较
  • 3.巧用Android Studio
  • 4.认识Kotlin基本类型
  • 5.走进Kotlin的数组
  • 6.走进Kotlin的集合
  • 7.集合问题
  • 8.完整代码
  • 9.基础语法在这里插入图片描述

第二章 Kotlin实战避坑指南

  • 2.1 方法入参是常量,不可修改
  • 2.2 不要 Companion 、INSTANCE ?
  • 2.3 Java 重载,在 Kotlin 中怎么巧妙过渡一下?
  • 2.4 Kotlin 中的判空姿势
  • 2.5 Kotlin 复写 Java 父类中的方法
  • 2.6 Kotlin “狠”起来,连TODO 都不放过!
  • 在这里插入图片描述

第三章 项目实战《Kotlin Jetpack实战》

  • 3.1 从一个膜拜大神的 Demo 开始
  • 3.2 Kotlin 写 Gradle 脚本是一种什么体验?
  • 3.3 Kotlin 编程的三重境界
  • 3.4 Kotlin 高阶函数
  • 3.5 Kotlin泛型
  • 3.6 Kotlin 扩展
  • 3.7 Kotlin 委托
  • 3.8 协程“不为人知”的调试技巧
  • 3.9 图解协程:suspend在这里插入图片描述
完整学习文档,可以扫描下方二维码免费领取!!!
  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin是一种现代的编程语言,它被设计为易于阅读和编写,同时提供了许多现代编程语言的功能。在数据处理方面,Kotlin提供了一些强大的工具和库,可以帮助开发者更有效地处理数据。 1. **集合类**:Kotlin提供了丰富的集合类,如List、Set、Map等,这些类提供了许多有用的方法来处理数据。例如,可以使用filter()方法过滤列表中的元素,使用map()方法将列表转换为映射,使用reduce()方法对列表进行累加等。 2. **扩展函数**:Kotlin的扩展函数是一种允许在集合类上定义新操作的技术,这使得处理数据更加简单和高效。例如,可以使用扩展函数对集合进行排序、去重、过滤等操作。 3. **流(Stream)**:Kotlin的流是处理数据的一个非常强大的工具。流是一种可以连续访问元素的数据结构,它提供了许多高级操作,如map、filter、reduce等。使用流,你可以轻松地对数据进行转换、过滤和汇总。 4. **DSL(领域特定语言)**:Kotlin的许多库(如SQL查询库、文件处理库等)都使用了DSL,这使得这些库的用法更加直观和简单。通过DSL,开发者可以更专注于数据处理逻辑,而不用花费太多精力在语法上。 5. **Kotlin协程**:Kotlin协程是Kotlin 1.5版本引入的一个新特性,它允许你在异步操作中管理并发和协程。这使得在数据处理中更有效地使用异步编程成为可能,从而提高程序的性能和响应性。 6. **DSL与标准库**:Kotlin提供了丰富的标准库,包括用于网络请求、文件操作、数据库访问等的功能。这些库通常提供了高级的API,使得数据处理变得更加简单和高效。 总的来说,Kotlin在数据处理方面提供了一个强大而灵活的生态系统,包括各种集合类、扩展函数、流、DSL和协程等工具,这些工具可以帮助开发者更有效地处理数据,提高代码的可读性和可维护性,同时降低代码的复杂度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值