Spring Framework 5.0 中導入 Kotlin 支援

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

更新:一個全面的 Spring Boot + Kotlin 教學 現在可用。

繼幾個月前我們在 start.spring.io 上引入 Kotlin 支援 之後,我們持續努力確保 Spring 和 Kotlin 能夠良好地協同運作。Kotlin 的主要優勢之一是,它為用 Java 編寫的程式庫提供了非常好的 互通性。但是,還有一些方法可以更進一步,允許在開發下一個 Spring 應用程式時編寫完全符合 Kotlin 習慣的程式碼。除了 Kotlin 應用程式可以利用的 Spring Framework 對 Java 8 的支援(例如函數式 Web 或 Bean 註冊 API)之外,還有其他 Kotlin 專用功能,應該可以讓您達到一個新的生產力水平。

這就是為什麼我們在 Spring Framework 5.0 中引入專用的 Kotlin 支援,並且我想在這篇部落格文章中總結一下,這些功能旨在使您在使用這些技術時獲得無縫的開發者體驗。您可以使用 這個連結 在 Spring Framework 錯誤追蹤器中找到與 Kotlin 相關的問題。

我們 Kotlin 支援的一個關鍵組成部分是 Kotlin 擴充功能。它們允許以非侵入方式擴充現有的 API,為公用程式類別或 Kotlin 特定的類別層次結構提供更好的替代方案,以便將 Kotlin 專用功能添加到 Spring。來自 Mario Arias 的一些程式庫(例如 KotlinPrimavera)已經展示了我們可以帶給 Spring API 的各種 Kotlin 助手,以便允許編寫更符合 Kotlin 習慣的程式碼。使用 Spring Framework 5,我們將 Spring Framework 依賴項中最有用和最流行的擴充功能整合在一起,並且我們正在添加新的擴充功能!請注意,Kotlin 擴充功能是靜態解析的,您必須匯入它們(就像 Java 中的靜態匯入一樣)。

##Spring Framework API 的 Null-safety

Spring Framework 5.0 為所有套件引入了正式的非空 API 宣告,具有明確的可為空引數和返回值,現在已如此標註。我們的可空性註釋符合 JSR 305,並且一旦 KT-10942 得到修復,Kotlin 將支援它們。這將使整個 Spring Framework API 從 Kotlin 方面來看是 null-safe 的,並且允許在編譯時處理空值,而不是在執行時拋出 NullPointerExceptions

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

最初基於來自 Raman Gupta 的社群貢獻,Spring 現在利用 Kotlin null-safety 支援 來確定是否需要 HTTP 參數,而無需明確定義 required 屬性。這表示 @RequestParam name: String? 將被視為非必要,而 @RequestParam name: String 將被視為必要。這也受到 Spring Messaging @Header 註釋的支援。

以類似的方式,使用 @Autowired@Inject 的 Spring Bean 注入使用此資訊來了解是否需要 Bean。@Autowired lateinit var foo: Foo 表示必須在應用程式上下文中註冊一個 Foo 類型的 Bean,而如果這樣的 Bean 不存在,則 @Autowired lateinit var foo: Foo? 不會引發錯誤。

##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 的新方法,作為 XML 或 JavaConfig 以及 @Configuration@Bean 的替代方案。簡而言之,它可以使用作為 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 提供方便的 API(感謝 Netflix 的 Jon Schneider 貢獻了此功能)以及新的 WebClient Spring WebFlux API。例如,要在 Java 中檢索 Foo 物件的清單,您必須編寫

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

而在具有 Spring Framework 5 擴充功能的 Kotlin 中,您將能夠編寫

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(例如 @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 宣布 他們將支援使用 Kotlin 而不是 Groovy 編寫建置和設定檔。這使得在您的 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 Framework 5.0 Kotlin 的支援,並產生一個 Spring Boot 2.0.0(里程碑版本或快照版本)專案,並在這裡或 Kotlin Slack#spring 頻道中向我們發送您的回饋。 您也可以 貢獻 您需要的 Kotlin 擴展 ;-)

獲取 Spring 電子報

隨時掌握 Spring 電子報的最新消息

訂閱

領先一步

VMware 提供培訓和認證,以加速您的進展。

了解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

了解更多

即將舉行的活動

查看 Spring 社群中所有即將舉行的活動。

查看所有