使用 Kotlin 開發 Spring Boot 應用程式

工程 | Sébastien Deleuze | 2016 年 2 月 15 日 | ...

更新:一份全面的Spring Boot + Kotlin 教程現已推出。

恰逢Kotlin 1.0 版本釋出之際,我們正在向https://start.spring.io新增 Kotlin 語言支援,以便更輕鬆地使用這種語言啟動新的 Spring Boot 專案。

這篇部落格文章也是一個機會,讓我解釋為什麼我覺得這種語言很有趣,向你詳細展示一個示例專案,並給你一些提示。

什麼是 Kotlin?

Kotlin 是由 JetBrains 建立的一種語言。它執行在 JVM 上(但不僅限於此),是一種面嚮物件語言,包含許多函數語言程式設計的思想。我不會過多詳細介紹所有 Kotlin 特性(PDFHTML),但我希望重點介紹一些我覺得最有趣的特性

  • Kotlin 是一種靜態型別語言,但憑藉其智慧的型別推斷,它允許你編寫像動態語言一樣簡潔富有表現力的程式碼,同時效能接近純 Java 專案
  • 支援屬性
  • 相比其他語言,標準庫相對輕量級
  • 易於學習:Java 開發者可以快速理解該語言的大部分內容(這份與 Java 的快速對比值得一讀)
  • Java 互操作性是一個首要關注點並且很棒
  • 非常適合 Android 開發
  • 內建不可變性及空安全支援
  • 程式碼易於閱讀,編寫高效
  • 允許擴充套件現有庫,無需繼承類或使用裝飾器等任何設計模式
  • 無需分號 ;-)

你可以在這篇Kotlin 2015 年摘要部落格文章中找到許多有用的連結來提升你的 Kotlin 知識。還可以看看這些簡單的Kotlin 練習,快速瞭解該語言。

一個 Spring Boot + Kotlin 示例專案

Kotlin 的設計旨在與 Java 生態系統良好協作,在我看來,它與 Spring Boot 擁有相同的務實、創新和有主見的思維模式,因此它們可以很好地協同工作。你可以看看這個簡單的Spring Boot + Spring Data JPA Kotlin 專案,更具體地瞭解它的樣子。

Kotlin 憑藉其非常簡潔的語法宣告,可以輕鬆編寫(和閱讀)你的領域模型。你可以看到 Kotlin 允許指定引數預設值,並且型別在變數/引數名稱之後宣告。

@Entity
class Customer(
	var firstName: String = "",
	var lastName: String = "",
	@Id @GeneratedValue(strategy = GenerationType.AUTO)
	var id: Long = 0
)

你在下面看到的 Spring MVC REST 控制器使用了建構函式級別的注入,並且 Kotlin 中的預設可見性是 public,因此無需指定。當函式返回單個表示式時,可以省略花括號,並在 = 符號後指定函式體。更好的是,返回型別可以由編譯器推斷。

@RestController
class CustomerController (val repository:CustomerRepository) {

	@GetMapping("/")
	fun findAll() = repository.findAll()

	@GetMapping("/{name}")
	fun findByLastName(@PathVariable name:String)
		= repository.findByLastName(name)
}

Spring Data Repository 是不言自明的

interface CustomerRepository : CrudRepository<Customer, Long> {
	fun findByLastName(name: String): List<Customer>
}

由於 Kotlin 支援頂級函式,你可以像這樣簡單地宣告你的應用程式

@SpringBootApplication
class Application {

	@Bean
	fun init(repository: CustomerRepository) = CommandLineRunner {
		repository.save(Customer("Jack", "Bauer"))
		repository.save(Customer("Chloe", "O'Brian"))
		repository.save(Customer("Kim", "Bauer"))
		repository.save(Customer("David", "Palmer"))
		repository.save(Customer("Michelle", "Dessler"))
	}
}

fun main(args: Array<String>) {
	SpringApplication.run(Application::class.java, *args)
}

你需要使用kotlin-spring 外掛,以便自動將 @Configuration 類以及一些其他 @Service@Repository 類標記為 open,因為在 Spring 中,由於使用了 CGLIB 代理,它們不能是 final(在 Kotlin 中,如果沒有 open 修飾符,類和方法預設是 final 的)。使用 JDK 動態代理的 Bean 不需要 open 修飾符。

額外提示

即使 Spring Boot 和 Kotlin 配合得很好,這些額外提示也值得了解。檢視關於改進 Spring Boot 中 Kotlin 支援的此問題瞭解更多詳情。

陣列註解屬性

與 Java 不同,Kotlin 當前不允許將陣列註解屬性指定為單個值(除了 value 屬性),因此請注意,你將不得不寫 @RequestMapping(method = arrayOf(RequestMethod.GET))@EnableAutoConfiguration(exclude = arrayOf(Foo::class))

預計此行為將在即將釋出的 Kotlin 1.2 中得到改進(詳見此 Kotlin issue)。Spring Framework 4.3 的組合註解,如 @GetMapping@PostMapping 也能提供幫助。

屬性注入

前面我們已經看到了如何進行建構函式注入,因為那是推薦的方法(尤其是在使用 Kotlin 時)。如果你必須進行屬性注入,則需要使用延遲初始化屬性,因為通常,宣告為非空型別的原始屬性必須在建構函式中初始化。

@RestController
class CustomerController {

	@Autowired
	lateinit var repository:CustomerRepository

	// ...
}

屬性佔位符

在 Kotlin 中,$ 用於字串插值,因此在使用屬性佔位符時應進行轉義:@Value("\${some.property}")。作為替代方案,你也可以使用@ConfigurationProperties,更多詳情請參閱此 Stack Overflow 回答。

Jackson Kotlin 模組

如果你使用 Jackson,你很可能希望新增com.fasterxml.jackson.module:jackson-module-kotlin依賴項,以便它能夠處理沒有預設建構函式的資料類或 Kotlin 集合。它將由 Spring Framework 4.3+ 自動註冊。

試試 Java 到 Kotlin 的轉換器

最後一條提示,IntelliJ IDEA 中提供的 Java 到 Kotlin 轉換器(選單 Code -> Convert Java file to Kotlin file)在你不知道如何在 Kotlin 中編寫某些內容時非常有用。因此,不要猶豫,先用 Java 編寫,然後用它來找到對應的 Kotlin 寫法。這份與 Java 的對比文件也能提供一些幫助。

反饋

我們很期待收到你關於使用 Kotlin 開發 Spring 應用程式的反饋。這篇部落格文章只是一個引子,還有很多要說,特別是關於如何在 Spring Boot 中使用更符合 Kotlin 習慣的程式碼,比如使用Exposed SQL 庫,敬請期待(更新:下一篇 Kotlin 部落格文章現已釋出,請點選此處檢視)...

訂閱 Spring 資訊

訂閱 Spring 資訊,保持聯絡

訂閱

領先一步

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

瞭解更多

獲取支援

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

瞭解更多

近期活動

檢視 Spring 社群的所有近期活動。

檢視全部