文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

在几个月前,我们宣布 Kotlin 已在 start.spring.io 中受支持后,我们继续努力希望实现 Spring 和 Kotlin 的更好共存。Kotlin 有一关键性能是能与 Java 库很好地互用,但要在 Spring 中编写惯用的 Kotlin 代码,还需要一段时间的发展。除了 Spring 对 Java 8 的支持让 Kotlin 受益(比如说函数式 Web 编程或是 bean 注册 API)之外,还应该有一些专为 Kotlin 准备的特性帮你提高生产力。

第 1 段(可获 1.34 积分)

这就是我们在 Spring Framework 5.0 M4 上专门为 Kotlin 引进支持的原因 , 在这篇博客中,我对这些特性做了一下总结,以帮助你更好地结合 Spring 和 Kotlin 使用。如果在过程中遇到问题,你能在此处查看 Spring bug 跟踪系统中与 Kotlin 相关的 issue。

利用 Kotlin 的 nullable 信息

最初基于来自于 Raman Gupta 的社区贡献,Spring 利用 Kotlin 对空值安全性的支持来判断 HTTP 参数是否是必需的,而不用去对必需的属性进行明确的定义。这就意味着 @RequestParam name: String? 会被看成是非必需,而 @RequestParam name: String 会是必需。这个也在 Spring Messaging 上的 @Header 注解中得到了支持。

第 2 段(可获 1.39 积分)

用同样的方式,Spring 使用 @Autowired 或者 @Inject 所进行的 Bean 注入也利用了这一信息来获悉一个 Bean 是否是必需的。@Autowired lateinit var foo: Foo 表示一个类型为 Foo 的 Bean 必需在应用程序上下文中被注册,而 @Autowired lateinit var foo: Foo? 则在这样一个 Bean 不存在的时候不会发生错误。

RestTemplate 和功能性 Web API 扩展

Kotlin 扩展能以非入侵的方式对现有的 API 进行扩展,为利用类或者 Kotlin 的特殊类层级结构提供一个更好的可选方案来向 Spring 加入 Kotlin 的专有功能特性。 一些类似于来自 Mario Arias 的 KotlinPrimavera 的库,已经展示了多样的 Kotlin 辅助程序,我们可以将它们引入到 Spring API , 从而写出更加优雅的代码。运用 Spring Framework 5,我们会在 Spring 框架依赖中集成最实用且最流行的扩展,而如今我们又多了一个新帮手!

第 3 段(可获 1.68 积分)

比如,Kotlin 具体类型参数为 JVM 范型类型消除提供了一种方法,因此,为了利用该特性,我们引入了一些扩展以提供更好的 API。

这样就能为 RestTemplate 提供便利的 API(感谢 Netflix 的 Jon Schneider 对此的贡献)。例如,要提取 Foo 对象的列表,你可以用 Java 这么写:

List<Foo> result = restTemplate.exchange(url, 
    HttpMethod.GET, 
    null, 
    new ParameterizedTypeReference<List<Foo>>() {}).getBody();

或者,你使用中间数组:

第 4 段(可获 0.9 积分)
List<Foo> result = Arrays.asList(restTemplate.getForObject(url, Foo[].class));

而使用了 Spring Framework 5 扩展,你可以能够用 Kotlin 来这样写:

val result : List<Foo> = restTemplate.getForObject(url)

要注意 Kotlin  的扩展是要进行静态解析的,所以你先将它们导入。在上面示例中 ,你需要添加使用 import org.springframework.web.client.RestOperationsExtension.getForObject 。 Kotlin 扩展通常由 IDE,如 IntelliJ IDEA(静态导入)自动建议,但它对于嵌套在容器对象中的扩展不起作用(在这一点上你可能比较看好 KT-15440),所以在问题修复之前,你必须手动导入 Spring Kotlin 扩展。

第 5 段(可获 1.09 积分)

RestTemplate 或功能性 web API 扩展目前在 Spring Framework 5.0 M4 中可用:

这些扩展也提供了成员函数,以支持本地 Kotlin KClass,因此,你可以指定 Foo::class 参数以代替Foo::class.java。

Reactor Kotlin 扩展

Reactor 是 Spring Framework 5.0 附带的响应式框架, 而在开发一个响应式 web 应用程序时,有许多时候可能会用上 MonoFlux 和 StepVerifier API 。

第 6 段(可获 0.91 积分)

因此今天我们也要藉由新的 reactor-kotlin 项目,来对 Reactor 中的 Kotlin 支持进行一下介绍! 它提供了能够通过写上 writingfoo.toMono() 来从任何类实例创建出 Mono 实例的扩展, 许多人会喜欢写成 Mono.just(foo)。它也支持诸如利用 stream.toFlux() 来从一个 Java 8 Stream 实例创建出一个 Flux。Iterable, CompletableFuture 以及 Throwable 扩展,还有基于 KClass 的 Reactor API 变体也得到了提供。

现在这个项目仍处于早期阶段, 因此如果你感觉这个项目还缺了点什么,请随意贡献出你自己的扩展吧。

第 7 段(可获 1.04 积分)

使用 Kotlin 进行功能性的 Bean 注册

Spring Framework 5.0 引入了一种注册 Bean 的新方法,作为利用 XML 或者 JavaConfig 的 @Configuration 或者 @Bean 的替代方案。简言之,它能实现用供应器 lambda 扮演工厂 Bean 的角色。

例如用 Java 代码你会这样写:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.registerBean(Foo.class);
context.registerBean(Bar.class, () -> new 
	Bar(context.getBean(Foo.class))
);

而使用 Kotlin, 因为被具象化的类型参数,我们可以将代码写成这样:

第 8 段(可获 0.78 积分)
val context = AnnotationConfigApplicationContext()
context.registerBean(Foo::class)
context.registerBean(Supplier {
	Bar(context.getBean(Foo::class))
})

您可以在  https://github.com/mix-it/mixit/ 上使用功能性 Webbean 注册 API 查看 Spring 应用程序的具体示例。

ApplicationContext 相关 Kotlin 扩展包括:

类声明不需要 open

到现在为止,使用 Kotlin 构建 Spring Boot 应用程序时遇到了几个问题,其中之一就是需要在每个类上添加一个 open 关键字,并且使用 CGLIB(如 @Configuration 类)代理它们的成员函数。这个需求的根本原因在于 Kotlin 的类是默认为 final

第 9 段(可获 1.24 积分)

好在 Kotlin 1.0.6 提供了 kotlin-spring 插件,可以用下列注解或元注解打开类或成员函数:

  • @Component
  • @Async
  • @Transactional
  • @Cacheable

元注解支持意味着使用 @Configuration,@Controller,@RestController,@Service 或 @Repository 注解的类会自动打开,因为这些注解使用了@Component。

我们更新了 start.spring.io 以在默认情况下启用。你可以阅读 Kotlin 1.0.6 博客来了解更多细节,如新的 kotlin-jpa 和 kotlin-noarg 插件。

第 10 段(可获 1.05 积分)

基于 Kotlin 的 Gradle 构建配置

今年 5 月份,Gradle 宣布他们将支持在 Groovy 和 Kotlin 中编写构建和配置文件。因此在 IDE 中实现自动完成和验证成为可能,因为这些文件通常是常规静态类型的 Kotlin 脚本文件。这很可能成为基于 Kotlin 的项目的自然选择,对 Java 项目也有很大价值。

自 5 月以来,gradle-script-kotlin 项目不断发展,但在使用前需要谨记以下两点:

  • 你需要使用 Kotlin 1.1-EAP IDEA 插件来支持自动完成功能(但如果你正在使用 kotlin-spring 插件,就需等待 Kotlin 1.1-M05,因为 1.1-M04 不能稳定地使用该插件)

  • 文档还不完善,但你可以在 Kotlin Slcak 上的 #gradle 频道中找 Gradle 团队寻求帮助。

Spring-boot-kotlin-demo 和 mixit 项目都是通过基于 Kotlin 的 Gradle 版本构建的,有兴趣可以看看。我们正在考虑在 start.spring.io 中添加这种支持。.

第 11 段(可获 1.71 积分)

Spring-boot-kotlin-demo 和 mixit 都是用基于 Kotlin 的 Gradle 版本构建的,你可自行查看。我们正在讨论是否要在 start.spring.io 中也添加这种支持。

基于模板的 Kotlin 脚本

从 4.3 版本开始,Spring Framework 提供了 ScriptTemplateView,用以利用支持 JSR-223 的脚本引擎来渲染模板。 Kotlin 1.1-M04 提供了这样的支持,并允许渲染基于 Kotlin 的模板,更为详细信息,请查看提交记录

由此也产生了一些有意思的使用案例,如使用 kotlinx.html DSL 编写类型安全模板或简单地使用 Kotlin 多 String 字符串插值, 正如 kotlin-script-templating 项目所演示的。你可以在 IDE 中编写具有自动完成功能和重构支持的一类模板:

第 12 段(可获 1.41 积分)
import io.spring.demo.User
import io.spring.demo.joinToLine

"""
${include("header", bindings)}
<h1>Title : $title</h1>
<ul>
    ${(users as List<User>).joinToLine{ "<li>User ${it.firstname} ${it.lastname}</li>" }}
</ul>
${include("footer")}
"""

这个功能仍在开发中,但我正在与 Kotlin 团队合作,以确保在 MVC 和 Spring Framework 5.0 GA 的 Reactive 中暂时能够与嵌套模板和支持 i18n 的功能一起工作。

总结

用 Kotlin 写 Spring Boot 应用越多,越是能感受到这两种技术具有相同的技术理念,它们能让你写出更具有表达力、更简洁、更易读的代码。Spring Framework 5 对 Kotlin 的支持,更是自然、简洁、有效地整合这些技术的重要进步。

第 13 段(可获 1.19 积分)

Kotlin 可以用来写基于注解的 Spring Boot 应用,同时也能够很好地和 Spring  Framework 5.0 中支持的新型功能性和反应性应用兼容。

Kotlin 工作组基本上都解决了我们反馈的问题,感谢他们的努力。马上就要发布的 Kotlin1.1 版本也将修改 KT-11235,以便允许指定阵列不使用 arrayof()就能赋予单值属性。主要遗留问题可能是 KT-4984,它要求指定特定的 lambda 类型,但其实你只需要指定一个 {} 就够了。

第 14 段(可获 1.26 积分)

请自由测试Spring Framework 5.0的Kotlin支持,可以去start.spring.io网站,并生成一个Spring Boot 2.0.0 (快照版本)的项目, 然后在这里将你的反馈意见发送给我们或者在Kotlin Slack #spring的频道上留言。你也可以贡献你所需要的Kotlin扩展 ;-)

第 15 段(可获 0.56 积分)

文章评论