KSP
KSP(Kotlin Symbol Processing)是 Kotlin 官方推出的编译期符号处理 API,用于在编译阶段读取、分析 Kotlin 代码结构并生成新代码,是替代 KAPT、实现高效注解处理与代码生成的核心方案。
一、KSP 是什么
KSP = Kotlin Symbol Processing,是一套轻量级编译器插件 API,专门处理 Kotlin 代码的符号信息(类、函数、属性、注解、泛型等),在编译期完成代码分析与生成,不侵入运行时。
核心定位
- 替代传统 Java Annotation Processing(AP) 与 KAPT,专为 Kotlin 设计
- 直接操作 Kotlin 符号模型,无需解析 Java 字节码
- 支持完整 Kotlin 特性:扩展函数、密封类、协程、声明点泛型、局部函数等
- 核心用途:注解处理、代码生成、编译期校验、元编程
与 KAPT 的关键区别
| 特性 | KSP | KAPT(Kotlin Annotation Processing Tool) |
|---|---|---|
| 底层 | 直接处理 Kotlin 符号 | 先将 Kotlin 转 Java stub,再用 Java AP 处理 |
| 性能 | 快(增量编译、无 stub 开销) | 慢(生成 stub、全量编译多) |
| Kotlin 支持 | 原生支持所有特性 | 仅支持 Java 兼容子集,丢失 Kotlin 信息 |
| API 复杂度 | 简洁、Kotlin 友好 | 繁琐、基于 Java 注解处理 API |
| 增量编译 | 原生支持,仅处理变更文件 | 支持有限,易触发全量编译 |
| 内存占用 | 低(按需加载符号) | 高(生成大量 stub) |
二、核心概念与架构
1. 核心组件
- SymbolProcessor:处理器入口,实现
SymbolProcessor接口,处理符号并生成代码 - SymbolProcessorProvider:用于发现与实例化处理器,SPI 机制加载
- Resolver:符号解析器,提供访问所有 Kotlin 符号的 API(类、函数、属性、注解等)
- CodeGenerator:代码生成器,输出新的 Kotlin/Java 源文件
- KSPLogger:编译期日志与错误上报
2. 处理流程
- 编译触发:Kotlin 编译启动,KSP 插件被加载
- 符号收集:Resolver 扫描源码,构建 Kotlin 符号树
- 处理器执行:
SymbolProcessor.process(resolver, generator)被调用 - 代码生成:通过 CodeGenerator 输出新源码
- 合并编译:生成的代码与原代码一起编译为字节码
三、核心 API 与符号模型
1. 核心符号类型
- KSClassDeclaration:类/接口/对象/枚举声明
- KSFunctionDeclaration:函数/方法声明
- KSPropertyDeclaration:属性/字段声明
- KSAnnotation:注解实例
- KSType:类型(含泛型、可空性、继承关系)
- KSValueParameter:函数参数
2. 常用 API 示例
// 1. 获取所有带 @MyAnnotation 的类
resolver.getSymbolsWithAnnotation(MyAnnotation::class.qualifiedName!!)
.filterIsInstance<KSClassDeclaration>()
.forEach { cls ->
// 读取类名、注解参数、父类、属性、函数等
val className = cls.simpleName.asString()
val annotation = cls.getAnnotationsByType(MyAnnotation::class).first()
val value = annotation.arguments.first().value as String
// ... 分析与生成逻辑
}
// 2. 生成 Kotlin 代码
generator.createNewFile(
dependencies = emptyList(), // 依赖文件
packageName = "com.example.generated",
fileName = "Generated_$className",
extensionName = "kt"
).writer().use { writer ->
writer.write("""
package com.example.generated
class Generated_$className {
fun hello() = println("Hello from $className")
}
""".trimIndent())
}
四、快速上手:开发 KSP 处理器
1. 环境配置(Gradle)
// 根目录 build.gradle
plugins {
id("com.google.devtools.ksp") version "1.9.20-1.0.14" apply false
}
// 模块 build.gradle(处理器模块)
plugins {
kotlin("jvm")
id("com.google.devtools.ksp")
}
dependencies {
implementation("com.google.devtools.ksp:symbol-processing-api:1.9.20-1.0.14")
ksp("com.google.devtools.ksp:symbol-processing-compiler:1.9.20-1.0.14")
}
// 启用 KSP 生成代码的源码目录
kotlin {
sourceSets.main {
kotlin.srcDir("build/generated/ksp/main/kotlin")
}
}
2. 定义注解
// 定义运行时/编译期注解
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE) // 仅编译期可见
annotation class GenerateHelper(val suffix: String = "Helper")
3. 实现 SymbolProcessor
class MyProcessor : SymbolProcessor {
override fun process(resolver: Resolver, generator: CodeGenerator, logger: KSPLogger) {
// 1. 查找所有带 @GenerateHelper 的类
val annotatedClasses = resolver.getSymbolsWithAnnotation(GenerateHelper::class.qualifiedName!!)
.filterIsInstance<KSClassDeclaration>()
annotatedClasses.forEach { cls ->
val clsName = cls.simpleName.asString()
val pkg = cls.packageName.asString()
val suffix = cls.getAnnotationsByType(GenerateHelper::class).first()
.arguments.first { it.name?.asString() == "suffix" }.value as String
val generatedName = "${clsName}$suffix"
// 2. 生成 Helper 类
generator.createNewFile(
dependencies = listOf(cls.containingFile!!),
packageName = pkg,
fileName = generatedName,
extensionName = "kt"
).writer().use {
it.write("""
package $pkg
class $generatedName(private val target: $clsName) {
fun sayHello() = println("Hello from $generatedName for ${clsName}!")
}
""".trimIndent())
}
}
}
}
4. 注册处理器(SPI)
在 src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider 文件中添加:
com.example.MyProcessorProvider
5. 实现 ProcessorProvider
class MyProcessorProvider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return MyProcessor()
}
}
6. 使用处理器
在业务模块添加依赖并启用 KSP:
plugins {
kotlin("jvm")
id("com.google.devtools.ksp")
}
dependencies {
// 依赖注解模块
implementation(project(":annotations"))
// 依赖处理器模块
ksp(project(":processor"))
}
使用注解触发生成:
@GenerateHelper(suffix = "Ext")
class User(val name: String, val age: Int)
// 编译后自动生成 UserExt 类
fun main() {
val user = User("Alice", 20)
val helper = UserExt(user)
helper.sayHello() // 输出:Hello from UserExt for User!
}
五、KSP 优势与适用场景
核心优势
- 性能飞跃:无 stub 生成、原生增量编译,编译速度提升 30%–80%
- Kotlin 原生:完整支持扩展函数、密封类、协程、泛型等特性
- API 简洁:基于 Kotlin 语法,学习成本低,代码更易维护
- 灵活扩展:支持生成 Kotlin/Java 代码,适配多平台(JVM/Android/JS/Native)
- 低内存占用:按需加载符号,避免全量解析
适用场景
- 注解驱动代码生成:如 Room、Retrofit、Dagger/Hilt、Jetpack Compose
- 编译期校验:检查注解使用规范、类型安全、命名规范
- 元编程:生成代理类、Builder、序列化/反序列化逻辑、接口实现
- 框架开发:构建依赖注入、ORM、RPC 等框架的核心逻辑
六、KSP2 新特性(最新版本)
- 架构重构:基于 Kotlin 编译器 API,不再是独立插件,与 IDE 共享符号模型
- 性能再提升:运行在 Gradle daemon,启动更快、增量更精准
- 更好调试:支持直接在测试中调用入口,调试流程简化
- 错误处理增强:优雅处理缺失类型,返回
ErrorType而非崩溃 - 多平台支持:更好适配 Kotlin Multiplatform
七、总结
KSP 是 Kotlin 生态编译期元编程的标准方案,以高性能、原生 Kotlin 支持、简洁 API 彻底替代 KAPT。它让注解处理与代码生成更高效、更易维护,是现代 Kotlin 框架(如 Compose、Room、Hilt)的底层核心技术。