領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多更新:現已提供一份全面的 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 的替代方案。簡而言之,它使得使用充當 FactoryBean 的 Supplier 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 擴充套件包括 BeanFactoryExtensions、ListableBeanFactoryExtensions、GenericApplicationContextExtensions 和 AnnotationConfigApplicationContextExtensions。
## RestTemplate 和 WebClient 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 擴充套件包括 RestOperationsExtensions、ServerRequestExtensions、BodyInsertersExtensions、BodyExtractorsExtensions、ClientResponseExtensions、ModelExtensions 和 ModelMapExtensions。
值得注意的是,像 Spring Data MongoDB 這樣的其他 Spring 專案也透過這些擴充套件為 Kotlin 提供了內建支援。
## Reactor Kotlin 內建支援
Reactor 是 Spring Framework 5.0 構建在其上的響應式基礎,在開發響應式 Web 應用程式時,您很有可能使用其 Mono、Flux 和 StepVerifier API。
因此,今天我們還在即將釋出的 Reactor 3.1 版本中引入了 Kotlin 內建支援!它提供了擴充套件,能夠透過編寫 foo.toMono() 從任何類例項建立 Mono 例項,許多人會更喜歡這種方式而不是 Mono.just(foo)。它還支援例如從 Java 8 Stream 例項建立 Flux,使用 stream.toFlux()。此外,還提供了 Iterable、CompletableFuture 和 Throwable 擴充套件,以及基於 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-jpa 和 kotlin-noarg 外掛。
## 基於 Kotlin 的 Gradle 構建配置
早在五月份,Gradle 就 宣佈 除了 Groovy 之外,還將支援使用 Kotlin 編寫構建和配置檔案。這使得在 IDE 中可以獲得完整的自動完成和驗證功能,因為這些檔案是常規的靜態型別 Kotlin 指令碼檔案。這很可能成為基於 Kotlin 的專案的自然選擇,但對於 Java 專案也同樣有價值。
自五月以來,kotlin-dsl Gradle 專案一直在不斷發展,現在可以使用,但要注意 2 個警告:
spring-boot-kotlin-demo 和 mixit 專案都使用了這樣的 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 擴充套件 ;-)