# 7.13. Kotlin 支持

[Kotlin](https://kotlinlang.org/)是一种针对 JVM（和其他平台）的静态类型语言，它允许编写简洁优雅的代码，同时提供与用 Java 编写的现有库的[互操作性。](https://kotlinlang.org/docs/reference/java-interop.html)

Spring Boot 通过利用其他 Spring 项目（如 Spring Framework、Spring Data 和 Reactor）中的支持来提供 Kotlin 支持。有关更多信息，请参阅[Spring Framework Kotlin 支持文档](https://docs.spring.io/spring-framework/docs/5.3.22/reference/html/languages.html#kotlin)。

开始使用 Spring Boot 和 Kotlin 的最简单方法是遵循[这个综合教程](https://spring.io/guides/tutorials/spring-boot-kotlin/)。您可以使用[start.spring.io](https://start.spring.io/#!language=kotlin)创建新的 Kotlin 项目。如果您需要支持，请随时加入[Kotlin Slack](https://slack.kotlinlang.org/)的#spring 频道，或者在[Stack Overflow](https://stackoverflow.com/questions/tagged/spring+kotlin)上使用`spring`和`kotlin`标签提出问题。

#### 7.13.1.要求

Spring Boot 至少需要 Kotlin 1.3.x，并通过依赖管理来管理合适的 Kotlin 版本。要使用 Kotlin，`org.jetbrains.kotlin:kotlin-stdlib`且`org.jetbrains.kotlin:kotlin-reflect`必须存在于类路径中。也可以使用`kotlin-stdlib`的变体`kotlin-stdlib-jdk7`和`kotlin-stdlib-jdk8`。

由于[Kotlin 类默认为 final](https://discuss.kotlinlang.org/t/classes-final-by-default/166)，您可能需要配置[kotlin-spring](https://kotlinlang.org/docs/reference/compiler-plugins.html#spring-support)插件以自动打开带有 Spring 注解的类，以便它们可以被代理。

在 Kotlin中序列化/反序列化 JSON 数据需要[Jackson 的 Kotlin 模块。](https://github.com/FasterXML/jackson-module-kotlin)在类路径中找到它时会自动注册。如果 Jackson 和 Kotlin 存在但 Jackson Kotlin 模块不存在，则会记录一条警告消息。

如果在[start.spring.io](https://start.spring.io/#!language=kotlin) 上引导 Kotlin 项目，则默认提供这些依赖项和插件。

#### 7.13.2. 空值安全

Kotlin 的主要功能之一是[null-safety](https://kotlinlang.org/docs/reference/null-safety.html)。它在编译时处理`null`值，而不是将问题推迟到运行时并遇到`NullPointerException`. 这有助于消除常见的错误来源，而无需使用`Optional`. Kotlin 还允许使用具有可为空值的函数构造，如本[Kotlin 中空安全综合指南中](https://www.baeldung.com/kotlin-null-safety)所述。

尽管 Java 不允许在其类型系统中表达 null 安全性，但 Spring Framework、Spring Data 和 Reactor 现在通过工具友好的注解为其 API 提供 null 安全性。默认情况下，Kotlin 中使用的 Java API 的类型被识别为放宽空检查的 [平台类型。](https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types)[Kotlin 对 JSR 305 注解](https://kotlinlang.org/docs/reference/java-interop.html#jsr-305-support)和可空性注解的支持为 Kotlin 中的相关 Spring API 提供了空值安全性。

可以通过添加`-Xjsr305`带有以下选项的编译器标志来配置 JSR 305 检查：`-Xjsr305={strict|warn|ignore}`. 默认行为与`-Xjsr305=warn` 相同。`strict`值需要在从 Spring API 推断的 Kotlin 类型中考虑空安全性，但应在知道 Spring API 可空性声明甚至在次要版本之间演变并且将来可能会添加更多检查的情况下使用该值）。

尚不支持泛型类型参数、可变参数和数组元素可空性。有关最新信息，请参阅[SPR-15942 。](https://jira.spring.io/browse/SPR-15942)另请注意，Spring Boot 自己的 API[尚未注解](https://github.com/spring-projects/spring-boot/issues/10712)。

#### 7.13.3. Kotlin API

**7.13.3.1. 运行应用程序**

Spring Boot 提供了一种惯用的方式来运行`runApplication<MyApplication>(*args)`应用程序，如以下示例所示：

```
@SpringBootApplication
class MyApplication
​
fun main(args: Array<String>) {
    runApplication<MyApplication>(*args)
}
```

这是`SpringApplication.run(MyApplication::class.java, *args)`的内部替代. 它还允许自定义应用程序，如以下示例所示：

```
runApplication<MyApplication>(*args) {
    setBannerMode(OFF)
}
```

**7.13.3.2. 扩展**

Kotlin[扩展](https://kotlinlang.org/docs/reference/extensions.html)提供了使用附加功能扩展现有类的能力。Spring Boot Kotlin API 利用这些扩展为现有 API 添加新的 Kotlin 特定便利。

提供了类似于 Spring Framework `RestOperations`为Spring Framework 提供的`TestRestTemplate`扩展。除其他外，这些扩展使利用 Kotlin 实体化类型参数成为可能。

#### 7.13.4. 依赖管理

为了避免在类路径上混合不同版本的 Kotlin 依赖项，Spring Boot 导入了 Kotlin BOM。

使用 Maven，可以通过设置`kotlin-maven-plugin`提供的`kotlin.version`属性来自定义 Kotlin . 通过 Gradle，Spring Boot 插件会自动与Kotlin 插件的`kotlin.version`版本对齐。

Spring Boot 还通过导入 Kotlin Coroutines BOM 来管理 Coroutines 依赖项的版本。可以通过设置`kotlin-coroutines.version`属性来自定义版本。 [如果一个 Kotlin 项目在start.spring.io](https://start.spring.io/#!language=kotlin)上至少有一个反应性依赖项，则默认情况下会提供`org.jetbrains.kotlinx:kotlinx-coroutines-reactor`依赖项。

#### 7.13.5. @ConfigurationProperties

当`@ConfigurationProperties`与[`@ConstructorBinding`](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.typesafe-configuration-properties.constructor-binding)具有不可变属性的支持类结合`val`使用时，如下例所示：

```
@ConstructorBinding
@ConfigurationProperties("example.kotlin")
data class KotlinExampleProperties(
        val name: String,
        val description: String,
        val myService: MyService) {
​
    data class MyService(
            val apiToken: String,
            val uri: URI
    )
}
```

要使用注解处理器 生成[您自己的元数据，](https://docs.spring.io/spring-boot/docs/current/reference/html/configuration-metadata.html#appendix.configuration-metadata.annotation-processor)[`kapt`应配置](https://kotlinlang.org/docs/reference/kapt.html)`spring-boot-configuration-processor`依赖项。请注意，由于 kapt 提供的模型的限制，某些功能（例如检测默认值或不推荐使用的项目）无法正常工作。

#### 7.13.6.测试

虽然可以使用 JUnit 4 来测试 Kotlin 代码，但 JUnit 5 默认提供并推荐使用。JUnit 5 允许一个测试类被实例化一次，并被重用于该类的所有测试。这使得在非静态方法上使用`@BeforeAll`和`@AfterAll`注解成为可能，这非常适合 Kotlin。

要模拟 Kotlin 类，建议使用[MockK](https://mockk.io/)。如果您需要`Mockk`等效的 Mockito 特定[`@MockBean`和`@SpyBean`注解](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing.spring-boot-applications.mocking-beans)，您可以使用提供类似`@MockkBean`和`@SpykBean`注解的[SpringMockK](https://github.com/Ninja-Squad/springmockk)。

#### 7.13.7.资源

**7.13.7.1. 进一步阅读**

* [Kotlin 语言参考](https://kotlinlang.org/docs/reference/)
* [Kotlin Slack](https://kotlinlang.slack.com/)（带有专用的#spring 频道）
* [Stackoverflow`spring`和`kotlin`标签](https://stackoverflow.com/questions/tagged/spring+kotlin)
* [在浏览器中试用 Kotlin](https://try.kotlinlang.org/)
* [博客](https://blog.jetbrains.com/kotlin/)
* [很棒的](https://kotlin.link/)
* [教程：使用 Spring Boot 和 Kotlin 构建 Web 应用程序](https://spring.io/guides/tutorials/spring-boot-kotlin/)
* [使用 Kotlin 开发 Spring Boot 应用程序](https://spring.io/blog/2016/02/15/developing-spring-boot-applications-with-kotlin)
* [带有 Kotlin、Spring Boot 和 PostgreSQL 的地理空间信使](https://spring.io/blog/2016/03/20/a-geospatial-messenger-with-kotlin-spring-boot-and-postgresql)
* [在 Spring Framework 5.0 中引入 Kotlin 支持](https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0)
* [Spring Framework 5 Kotlin API，函数式方式](https://spring.io/blog/2017/08/01/spring-framework-5-kotlin-apis-the-functional-way)

**7.13.7.2. 例子**

* [spring-boot-kotlin-demo](https://github.com/sdeleuze/spring-boot-kotlin-demo)：常规 Spring Boot + Spring Data JPA 项目
* [mixit](https://github.com/mixitconf/mixit)：Spring Boot 2 + WebFlux + Reactive Spring Data MongoDB
* [spring-kotlin-fullstack](https://github.com/sdeleuze/spring-kotlin-fullstack)：WebFlux Kotlin fullstack 示例，前端使用 Kotlin2js 而不是 JavaScript 或 TypeScript
* [spring-petclinic-kotlin](https://github.com/spring-petclinic/spring-petclinic-kotlin)：Spring PetClinic 示例应用程序的 Kotlin 版本
* [spring-kotlin-deepdive](https://github.com/sdeleuze/spring-kotlin-deepdive)：从 Boot 1.0 + Java 到 Boot 2.0 + Kotlin 的逐步迁移
* [spring-boot-coroutines-demo](https://github.com/sdeleuze/spring-boot-coroutines-demo) : 协程示例项目

###
