Spring Framework 5.0 中的 Kotlin 支援簡介

工程 | Sébastien Deleuze | 2017年01月04日 | ...

更新:現已提供一份全面的 Spring Boot + Kotlin 教程

繼我們幾個月前在 start.spring.io 上推出 Kotlin 支援 之後,我們繼續努力確保 Spring 和 Kotlin 能夠良好地協同工作。Kotlin 的主要優勢之一是它與 Java 編寫的庫具有非常好的 互操作性。但是,還有更進一步的方法,可以在開發下一個 Spring 應用程式時編寫完全慣用的 Kotlin 程式碼。除了 Spring Framework 對 Java 8 的支援(Kotlin 應用程式可以利用其函式式 Web 或 Bean 註冊 API)之外,還有專門針對 Kotlin 的附加功能,它們應該能讓您達到新的生產力水平。

因此,我們在 Spring Framework 5.0 中引入了專門的 Kotlin 支援,我將在本博文中總結這些功能,這些功能旨在讓您在將這些技術結合使用時獲得無縫的開發體驗。您可以使用 此連結在 Spring Framework 錯誤跟蹤器中查詢與 Kotlin 相關的問題。

我們 Kotlin 支援的一個關鍵構建塊是 Kotlin 擴充套件。它們允許以非侵入性的方式擴充套件現有 API,從而為實用工具類或特定於 Kotlin 的類層次結構提供更好的替代方案,以向 Spring 新增特定於 Kotlin 的功能。像 Mario Arias 的 KotlinPrimavera 這樣的庫已經展示了我們可以為 Spring API 帶來的各種 Kotlin 助手,以便編寫更慣用的程式碼。透過 Spring Framework 5,我們將最有用和最受歡迎的擴充套件整合到 Spring Framework 依賴項中,並且我們還在新增新的擴充套件!請注意,Kotlin 擴充套件是靜態解析的,您需要匯入它們(類似於 Java 中的靜態匯入)。

## Spring Framework API 的空安全

Spring Framework 5.0 為所有包引入了正式的非空 API 宣告,現在將明確可空的引數和返回值進行了相應註解。我們的可空性註解符合 JSR 305 標準,並且一旦 KT-10942 修復,Kotlin 將會支援它們。這將使整個 Spring Framework API 從 Kotlin 端實現空安全,並允許在編譯時處理空值,而不是在執行時丟擲 NullPointerExceptions

## 在 Spring 註解中利用 Kotlin 的可空資訊

Spring 最初基於 Raman Gupta 的社群貢獻,現在利用 Kotlin 的空安全支援 來確定 HTTP 引數是否是必需的,而無需顯式定義 required 屬性。這意味著 @RequestParam name: String? 將被視為非必需,而 @RequestParam name: String 將被視為必需。Spring Messaging 的 @Header 註解也支援此功能。

類似地,使用 @Autowired@Inject 的 Spring Bean 注入利用此資訊來了解 Bean 是否是必需的。@Autowired lateinit var foo: Foo 暗示應用程式上下文中必須註冊一個型別為 Foo 的 Bean,而 @Autowired lateinit var foo: Foo? 在不存在此類 Bean 時不會引發錯誤。

## Spring WebFlux 函式式 DSL

Spring Framework 5.0 附帶了一個 Kotlin 路由 DSL,它允許您利用最近釋出的 Spring 函式式 Web API,並用簡潔慣用的 Kotlin 程式碼編寫。

router {
    ("/blog" and accept(TEXT_HTML)).nest {
        GET("/", fooHandler::findAllView)
        GET("/{slug}", fooHandler::findOneView)
    }
    ("/api/blog" and accept(APPLICATION_JSON)).nest {
        GET("/", barHandler::findAll)
        GET("/{id}", barHandler::findOne)
    }
}

感謝 Yevhenii Melnyk 的早期原型和幫助!您可以在 https://github.com/mixitconf/mixit/Spring Boot 應用程式的實際示例 中看到使用函式式 Web API 的例子。

## 函式式 Bean 宣告 DSL

Spring Framework 5.0 引入了一種新的 Bean 註冊方式,使用 lambda 作為 XML 或 @Configuration@Bean 的 JavaConfig 的替代方案。簡而言之,它使得使用充當 FactoryBeanSupplier lambda 來註冊 Bean 成為可能。

在 Java 中,您可能會這樣寫

GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(Foo.class);
context.registerBean(Bar.class, () -> new 
	Bar(context.getBean(Foo.class))
);

而在 Kotlin 中,可重構型別引數和 函式式 Bean 宣告 DSL 使我們能夠簡單地這樣寫

beans {
    bean<Foo>()
    bean { Bar(ref()) }
}

可用的 ApplicationContext 相關 Kotlin 擴充套件包括 BeanFactoryExtensionsListableBeanFactoryExtensionsGenericApplicationContextExtensionsAnnotationConfigApplicationContextExtensions

## RestTemplateWebClient API 的擴充套件

例如,Kotlin 的可重構型別引數為 JVM 的 泛型型別擦除提供了變通方法,因此我們引入了一些擴充套件來利用此功能,從而在可能的情況下提供更好的 API。

這允許為 RestTemplate(例如,感謝 Netflix 的 Jon Schneider 的貢獻)和新的 WebClient Spring WebFlux API 提供方便的 API。例如,在 Java 中檢索 Foo 物件列表需要這樣寫:

Flux<User> users  = client.get().retrieve().bodyToFlux(User.class)

而在 Kotlin 中,使用 Spring Framework 5 擴充套件,您將能夠這樣寫:

val users = client.get().retrieve().bodyToFlux<User>()
// or (both are equivalent)
val users : Flux<User> = client.get().retrieve().bodyToFlux()

與 Java 一樣,在 Kotlin 中,users 是強型別的,但 Kotlin 巧妙的型別推斷允許更簡潔的語法。

Spring Framework 5.0 中可用的 Web API Kotlin 擴充套件包括 RestOperationsExtensionsServerRequestExtensionsBodyInsertersExtensionsBodyExtractorsExtensionsClientResponseExtensionsModelExtensionsModelMapExtensions

值得注意的是,像 Spring Data MongoDB 這樣的其他 Spring 專案也透過這些擴充套件為 Kotlin 提供了內建支援。

## Reactor Kotlin 內建支援

Reactor 是 Spring Framework 5.0 構建在其上的響應式基礎,在開發響應式 Web 應用程式時,您很有可能使用其 MonoFluxStepVerifier API。

因此,今天我們還在即將釋出的 Reactor 3.1 版本中引入了 Kotlin 內建支援!它提供了擴充套件,能夠透過編寫 foo.toMono() 從任何類例項建立 Mono 例項,許多人會更喜歡這種方式而不是 Mono.just(foo)。它還支援例如從 Java 8 Stream 例項建立 Flux,使用 stream.toFlux()。此外,還提供了 IterableCompletableFutureThrowable 擴充套件,以及基於 KClass 的 Reactor API 變體。

## 不再需要將 Bean 類宣告為 open

到目前為止,使用 Kotlin 構建 Spring Boot 應用程式時遇到的少數痛點之一是需要為 CGLIB 代理的 Spring Bean(如 @Configuration 類)的每個類及其成員函式新增 open 關鍵字。此要求的根本原因是,在 Kotlin 中,類預設是 final 的

幸運的是,Kotlin 1.0.6 現在提供了一個 kotlin-spring 外掛,該外掛預設開啟被以下註解或元註解註解的類的及其成員函式

  • @Component
  • @Async
  • @Transactional
  • @Cacheable

元註解支援意味著用 @Configuration@Controller@RestController@Service@Repository 註解的類會被自動開啟,因為這些註解都用 @Component 進行了元註解。

我們已更新 start.spring.io 以預設啟用它。您可以檢視 Kotlin 1.0.6 的這篇博文 以獲取更多詳細資訊,包括與 Spring Data 實體一起使用的 kotlin-jpakotlin-noarg 外掛。

## 基於 Kotlin 的 Gradle 構建配置

早在五月份,Gradle 就 宣佈 除了 Groovy 之外,還將支援使用 Kotlin 編寫構建和配置檔案。這使得在 IDE 中可以獲得完整的自動完成和驗證功能,因為這些檔案是常規的靜態型別 Kotlin 指令碼檔案。這很可能成為基於 Kotlin 的專案的自然選擇,但對於 Java 專案也同樣有價值。

自五月以來,kotlin-dsl Gradle 專案一直在不斷發展,現在可以使用,但要注意 2 個警告:

  • 您需要 Kotlin 1.1 IDEA 外掛才能獲得自動完成功能。
  • 文件尚不完整,但 Gradle 團隊在 Kotlin Slack 的 #gradle 頻道中非常樂於助人,並且應該在 1.0 版本釋出之前得到改進。

spring-boot-kotlin-demomixit 專案都使用了這樣的 Kotlin Gradle 構建,因此請隨意檢視。我們正在 討論 在 start.spring.io 上新增此類支援。

## 基於 Kotlin 指令碼的模板

從 4.3 版本開始,Spring Framework 提供了一個 ScriptTemplateView 來渲染支援 JSR-223 的指令碼引擎的模板,Spring Framework 5.0 更進一步,支援 i18n 和巢狀模板。Kotlin 1.1 提供了此類支援,並允許渲染基於 Kotlin 的模板,有關詳細資訊,請參閱 此提交

這使得一些有趣的用例成為可能,例如使用 kotlinx.html DSL 或簡單地帶有插值的 Kotlin 多行 String 來編寫型別安全的模板,如這個 kotlin-script-templating 專案所示。這可以讓你編寫這類模板,並在 IDE 中獲得完整的自動完成和重構支援。

import io.spring.demo.*

"""
${include("header")}
<h1>${i18n("title")}</h1>
<ul>
    ${users.joinToLine{ "<li>${i18n("user")} ${it.firstname} ${it.lastname}</li>" }}
</ul>
${include("footer")}
"""

## 結論

我用 Kotlin 編寫 Spring Boot 應用程式越多,我就越覺得這兩種技術有相同的理念,並能讓你編寫更高效的應用程式,程式碼富有表現力、簡潔且易於閱讀,而 Spring Framework 5 的 Kotlin 支援是朝著自然、簡單而強大的方式結合這些技術邁出的重要一步。

Kotlin 可以用於編寫 基於註解的 Spring Boot 應用程式,並且也同樣適用於 Spring Framework 5.0 將實現的 函式式和響應式應用程式 的新型別。

Kotlin 團隊在修復我們報告的幾乎所有痛點方面都做得非常出色,因此非常感謝他們。即將釋出的 Kotlin 1.2 版本預計還將修復 KT-11235,以便在不使用 arrayOf() 的情況下為陣列註解屬性指定單個值。您可能面臨的主要剩餘問題是 KT-14984,它需要明確指定 lambda 型別,而僅僅指定 { } 應該就足夠了。

請透過訪問 start.spring.io 並生成一個 Spring Boot 2.0.0 (里程碑或快照) 專案來測試 Spring Framework 5.0 的 Kotlin 支援,並在此處或 Kotlin Slack#spring 頻道中向我們提供反饋。您也可以 貢獻 您需要的 Kotlin 擴充套件 ;-)

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有