首页 » 漏洞 » Spring Framework 5.0 对 Kotlin 支持的介绍

Spring Framework 5.0 对 Kotlin 支持的介绍

 

继几个月前公布 Kotlin 已在 start.spring.io 中受支持 后,我们继续努力以实现 Spring 和  Kotlin 的更好共存。Kotlin 的一个重要的特性是能与 Java 库很好地 互用 ,但想要在 Spring 中编写原汁原味的 Kotlin 代码,还有一段路要走。除了 Spring 对 Java 8 的支持让 Kotlin 受益(比如说函数式 Web 编程或是 bean 注册 API)之外,还应该有一些专为 Kotlin 准备的特性来让你的生产力提升一个档次。

这就是为什么我们在 Spring Framework 5.0 M4 上专门为 Kotlin 引进支持。我在这篇博客中对这些特性做了一下总结,好让你更顺滑地结合 Spring 和 Kotlin 使用。如果在过程中遇到问题,你能在 这里 找到 Spring bug 跟踪系统里与 Kotlin 相关的 issue。

我们对 Kotlin 支持中的一个关键构造块就是 Kotlin 扩展 。它们能对现有的 API 实现非侵入式的扩展,为利用类或者 Kotlin 的特殊类层级结构,以此提供一个更好的可选方案来向 Spring 加入 Kotlin 的专有功能特性。一些像来自于  Mario AriasKotlinPrimavera 的库,已经展示了各种各样的 Kotlin 辅助程序,我们可以将它们引入到 Spring API , 从而写出更加优雅的代码。运用 Spring Framework 5,我们会在 Spring 框架依赖中集成最实用且最流行的扩展,而如今我们又多了一个新帮手!要注意 Kotlin  的扩展是要进行静态解析的,所以你先将它们导入(就像 Java 中的静态导入一样)。

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

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

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

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

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

val context = GenericApplicationContext {     registerBean<Foo>()     registerBean { Bar(it.getBean<Foo>()) } }

你可以在 https://github.com/mix-it/mixit/ 看到一个同时使用了  web 和  bean 注册 API 的 Spring 应用程序的具体示例。

跟 Kotlin 扩展相关的可用 ApplicationContext 有 BeanFactoryExtensions , ListableBeanFactoryExtensionsGenericApplicationContextExtensions 以及  AnnotationConfigApplicationContextExtensions

如何用 Kotlin 的方式使用 Spring Web 的功能性 API

Spring Framework 5.0 带来的 RouterFunctionDsl 可以让你使用干净且优雅的 Kotlin 代码来运用最近才推出的 Spring 功能性 Web API

fun route(request: ServerRequest) = RouterFunctionDsl {     accept(TEXT_HTML).apply {             (GET("/user/") or GET("/users/")) { findAllView() }             GET("/user/{login}") { findViewById() }     }     accept(APPLICATION_JSON).apply {             (GET("/api/user/") or GET("/api/users/")) { findAll() }             POST("/api/user/") { create() }             POST("/api/user/{login}") { findOne() }     }  } (request)

利用 Kotlin 可为空(nullable) 信息

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

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

RestTemplate 和功能性 Web API 扩展

例如, Kotlin 被具象化的类型参数 提供了一种用于 JVM  泛型类型擦除 的方法, 因此我们引入了一些扩展来对该特性加以利用,以尽可能提供一个更好的 API。

这样就能实现提供用于 RestTemplate 的便利 API (感谢 Netflix 的 Jon Schneider 对此的贡献)。例如,要提取一个 Foo 对象的列表,用 Java 代码你要这样写:

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

或者如果你使用了一个中间人数组,就用这种方式写:

List<Foo> result = Arrays.asList(restTemplate.getForObject(url, Foo[].class));

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

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

Spring Framework 5.0 中可用的 Web API Kotlin 扩展有 RestOperationsExtensions , ServerRequestExtensionsBodyInsertersExtensionsBodyExtractorsExtensions , ClientResponseExtensionsModelExtensions 以及  ModelMapExtensions

这些扩展也提供了支持本地 Kotlin KClass 的成员函数,让你可以指定 Foo::class 参数而不是 Foo::class.java。

Reactor Kotlin 扩展

Reactor 是 Spring Framework 5.0 附带的响应式框架, 而在开发一个响应式 web 应用程序时,有不少可以利用上  MonoFlux 和  StepVerifier API 的好机会。

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

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

类声明不再需要 open

到现在为止,使用 Kotlin 构建 Spring Boot 应用程序时遇到了几个问题,其中之一就是需要在每个类上添加一个 open 关键字,并且使用 CGLIB(如 @Configuration 类)代理它们的成员函数。这个需求的根本原因在于 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 博客 来了解更多细节,如新的 kotlin-jpa 和 kotlin-noarg 插件。

基于 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 中添加这种支持。

基于模板的 Kotlin 脚本

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

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

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 的支持,更是自然、简洁、有效地整合这些技术的重要一步。

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

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

欢迎到 start.spring.io 建立一个 Spring Boot 2.0.0 项目来体验 Spring Framework 5.0 对 Kotlin 的支持,您可以将您的反馈发送到这里,或者是发送到 Kotlin Slack 的 #spring 频道。您也可以将您需要的 Kotlin 扩展 投稿

原文链接:Spring Framework 5.0 对 Kotlin 支持的介绍,转载请注明来源!

0