领先一步
VMware 提供培训和认证,助你加速进步。
了解更多更新:一份全面的Spring Boot + Kotlin 教程现已推出。
恰逢Kotlin 1.0 版本发布之际,我们正在向https://start.spring.io添加 Kotlin 语言支持,以便更轻松地使用这种语言启动新的 Spring Boot 项目。
这篇博客文章也是一个机会,让我解释为什么我觉得这种语言很有趣,向你详细展示一个示例项目,并给你一些提示。
Kotlin 是由 JetBrains 创建的一种语言。它运行在 JVM 上(但不仅限于此),是一种面向对象语言,包含许多函数式编程的思想。我不会过多详细介绍所有 Kotlin 特性(PDF,HTML),但我希望重点介绍一些我觉得最有趣的特性
你可以在这篇Kotlin 2015 年摘要博客文章中找到许多有用的链接来提升你的 Kotlin 知识。还可以看看这些简单的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,你很可能希望添加com.fasterxml.jackson.module:jackson-module-kotlin
依赖项,以便它能够处理没有默认构造函数的数据类或 Kotlin 集合。它将由 Spring Framework 4.3+ 自动注册。
最后一条提示,IntelliJ IDEA 中提供的 Java 到 Kotlin 转换器(菜单 Code -> Convert Java file to Kotlin file)在你不知道如何在 Kotlin 中编写某些内容时非常有用。因此,不要犹豫,先用 Java 编写,然后用它来找到对应的 Kotlin 写法。这份与 Java 的对比文档也能提供一些帮助。
我们很期待收到你关于使用 Kotlin 开发 Spring 应用程序的反馈。这篇博客文章只是一个引子,还有很多要说,特别是关于如何在 Spring Boot 中使用更符合 Kotlin 习惯的代码,比如使用Exposed SQL 库,敬请期待(更新:下一篇 Kotlin 博客文章现已发布,请点击此处查看)...