使用 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 社区的所有近期活动。

查看全部