我们几个月前有介绍关于 Kotlin在start.spring.io上的支持 ,我们有一直在进行工作,以确保Spring和 Kotlin 在一起玩得很好。 Kotlin的一个关键优势是它提供了一个与用Java编写的库之间非常好的 互操作性 。但是有更多的方法可以进一步,允许编写完全成熟的Kotlin代码,当开发您的下一个Spring应用程序。除了Spring Framework对Java 8的支持,Kotlin应用程序可以利用类似功能的Web或bean注册API,还有其他Kotlin专用功能,应该可以让你的生产力水平达到一个新的高度。

这就是为什么我们在 Spring Framework 5.0 M4 中引入了一个专门的Kotlin支持,我想在这篇博客中总结的功能,旨在使您的开发人员体验无缝的在Spring中一起使用这些技术。你可以使用 这个链接 在Spring Framework bug tracker中查找Kotlin的相关问题。

利用Kotlin可空信息(nullable information)

Spring最初基于来自 Raman Gupta 的社区贡献,现在利用 Kotlin null-safety support 以确定是否需要HTTP参数,而不必显式地定义 required 属性。 这意味着 @RequestParam name:String? 被视为不需要(not required), @RequestParam name:String 视为必需。 这也支持Spring消息 @Header 注解。

以类似的方式,使用 @Autowired 或 @Inject 的Spring bean注入使用此信息来知道是否需要bean。 @Autowired lateinit var foo:Foo 意味着 Foo 类型的bean必须在应用程序上下文中注册,而 @Autowired lateinit var foo:Foo? 不会引发错误,如果这样的bean不存在。

RestTemplate和Functional Web API的扩展

Kotlin extensions 允许以非侵入方式扩展现有的API,提供了一个更好的替代实用程序类或在Kotlin特定类层次结构中添加Kotlin专用功能到Spring中。一些类似 Mario Arias 的 KotlinPrimavera 已经展示了我们可以带给Spring的各种Kotlin助手API,以允许编写更多的惯用代码。使用Spring Framework 5,我们集成了Spring框架中最有用和最受欢迎的扩展,并添加了新的扩展。

例如, Kotlin reified type parameters 为JVM泛型类型擦除提供了一个解决方法,因此我们介绍了一些扩展,以利用此功能在可能的情况下提供更好的API。

这允许为RestTemplate提供方便的API(感谢来自Netflix的 Jon Schneider 为此做出贡献)。例如,要在Java中检索“Foo”对象的列表,必须写:

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

或者,如果你使用中间数组:

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

而在Kotlin与Spring Framework 5扩展中,你将能够写:

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

请注意,Kotlin扩展名是静态解析的,你必须导入它们。 在上面的示例中,您需要添加 import org.springframework.web.client.RestOperationsExtension.getForObject 才能使用它。 Kotlin扩展通常由IDE(如IntelliJ IDEA)(如静态导入)自动建议,但对于嵌套在容器 object 中的扩展,它仍然无效(您可以投票KT-15440),所以直到它被修复,你将不得不手动添加Spring Kotlin扩展导入。

Spring Framework 5.0 M4中目前可用的“RestTemplate”或功能性Web API扩展包括:

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

Reactor Kotlin extensions

Reactor 是Spring Framework 5.0的反应基础,并且有很好的机会你将使用它的 Mono , Flux 和[StepVerifier] 开发reactive Web应用程序时的API。

所以今天我们还通过新的 reactor-kotlin 项目在Reactor中引入Kotlin支持!它提供了扩展,能够通过写入 foo.toMono() 从任何类实例创建 Mono 实例,许多人喜欢 Mono.just(foo) 。它还支持例如使用 stream.toFlux() 从Java 8 Stream 实例创建 Flux 。还提供了 Iterable , CompletableFuture 和 Throwable 扩展以及基于KClass的Reactor API变体。

这仍然是这个项目的早期,所以如果你想提供没有的功能,随时自由地 贡献 你自己的扩展。

Functional bean registration with Kotlin

Spring Framework 5.0引入了一种新的方式来注册bean,使用lambda作为XML或JavaConfig的替代,使用 @Configuration 和 @Bean 。 简而言之,它使得有可能注册bean与一个 Supplier lambda,充当一个 FactoryBean 。

在Java中,你将会写如下的代码:

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

而在Kotlin中,reified类型参数允许我们简单地写:

val context = AnnotationConfigApplicationContext()
context.registerBean(Foo::class)
context.registerBean(Supplier {
	Bar(context.getBean(Foo::class))
})

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

ApplicationContext 相关Kotlin可用扩展如下:

No need to declare your bean class as open anymore

直到现在,使用Kotlin构建Spring Boot应用程序时遇到的几个问题之一是需要在每个类上添加一个 open 关键字,并且使用CGLIB(如 @Configuration 类)来代替Spring bean的成员函数。 这个需求的根本原因来自于事实,在Kotlin, classes are final by default 。

幸运的是,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 插件对Spring Data实体非常有用。

Kotlin based Gradle build configuration

回到5月,Gradle 宣布 ,他们将支持在Groovy之外的Kotlin中编写构建和配置文件。这使得可以在IDE中具有完全自动完成和验证,因为这些文件是常规静态类型的Kotlin脚本文件。这很可能成为基于Kotlin的项目的自然选择,但这也对Java项目也很有价值。

自5月以来, gradle-script-kotlin 项目不断发展,现在可以使用2个警告:

  • 你需要Kotlin 1.1-EAP IDEA插件来获得自动完成(但如果你使用 kotlin-spring 插件,因为 1.1-M04 不能可靠地使用这个插件,等待Kotlin 1.1-M05 )
  • 文档不完整,但Gradle团队对Kotlin Slack的#gradle频道非常有帮助。

两个 spring-boot-kotlin-demo 项目使用这种基于Kotlin的Gradle构建,可以随意看看。我们)在start.spring.io 讨论 上添加了这样的支持。

Kotlin Script based templates

从4.3版本开始,Spring Framework提供了一个 ScriptTemplateView 使用支持 JSR-223 的脚本引擎来渲染模板。 K

这使得出现了一些有趣的使用情况,如使用 kotlinx.html DSL或简单的Kotlin multiline(多线)’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团队合作,暂时使其准备好对Spring Framework 5.0 GA上的嵌套模板和i18n在MVC和Reactive两方面的支持。

结语

我使用Kotlin编写Spring Boot应用程序越多,我觉得这两种技术有着共同的目标,允许您使用表达性,简短和可读的代码来更高效地编写应用程序,而Spring Framework 5 Kotlin支持将这些技术以更加自然,简单和强大的方式来展现给我们。

Kotlin可以用来编写 基于注解的Spring Boot应用程序 ,但作为一种新的 functional and reactive applications 也将是一种很好的尝试,Spring Framework 5.0将会启用。

Kotlin团队做了一个伟大的工作,修复几乎所有的bug点,我们报告,所以非常感谢他们。即将到来的Kotlin 1.1版本预计也修复 KT-11235 ,以允许指定数组注解标记单个属性值,无须使用 arrayOf() 。你将面临的主要问题可能是 KT-14984 ,它将需要明确指定lambda类型(如 Supplier {} 或 HandlerFunction {} )其中只需指定 {} 应该就足够了。

通过转到 start.spring.io 并生成一个Spring Boot 2.0.0(SNAPSHOT) 项目,可以自由测试Spring Framework 5.0 Kotlin支持并在这里或者在 Kotlin Slack 的“#spring”频道向我们发送您的反馈。你也可以 贡献 你需要的Kotlin扩展;-)