在 Spring Framework 5.0 中引入 Kotlin 支援

工程 | Sébastien Deleuze | 2017 年 1 月 4 日 | ...

更新:一個全面的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,為向 Spring 新增 Kotlin 專屬功能提供了比工具類或 Kotlin 特定類層次結構更好的替代方案。一些庫,例如來自Mario AriasKotlinPrimavera,已經展示了我們可以為 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 可空資訊

最初基於社群貢獻者 Raman Gupta 的貢獻,Spring 現在利用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/ 看到使用函式式 Web API 的 Spring Boot 應用的具體示例。

## 函式式 bean 宣告 DSL

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

在 Java 中,例如您可以這樣寫:

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

而在 Kotlin 中,實化型別引數(reified type parameters)和函式式 bean 宣告 DSL 讓我們只需這樣寫:

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

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

## RestTemplateWebClient API 的擴充套件

例如,Kotlin 實化型別引數為 JVM 泛型型別擦除提供了一種解決方案,因此我們引入了一些擴充套件來利用此特性,以便在可能的情況下提供更好的 API。

這使得能夠為 RestTemplate 提供便捷的 API(感謝 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 專案,例如 Spring Data MongoDB,也內建了對 Kotlin 的支援,並提供了此類擴充套件。

## Reactor 內建 Kotlin 支援

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

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

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

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

幸運的是,Kotlin 1.0.6 現在提供了一個 kotlin-spring 外掛,對於使用以下註解之一進行註解或元註解的類,預設會將其類及其成員函式設定為 open:

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

元註解支援意味著使用 @Configuration@Controller@RestController@Service@Repository 註解的類會自動設定為 open,因為這些註解使用 @Component 進行了元註解。

我們已經更新了 start.spring.io,使其預設啟用此功能。您可以檢視這篇 Kotlin 1.0.6 部落格文章瞭解更多詳情,包括與 Spring Data 實體非常有用新的 kotlin-jpakotlin-noarg 外掛。

## 基於 Kotlin 的 Gradle 構建配置

回顧五月,Gradle 宣佈他們將支援除了 Groovy 之外,使用 Kotlin 編寫構建和配置檔案。這使得您可以在 IDE 中獲得完整的自動補全和驗證,因為這些檔案是常規的靜態型別 Kotlin Script 檔案。這很可能成為基於 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 Script 的模板

從 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 社群的所有即將到來的活動。

檢視全部