在 Spring Framework 5.0 中引入 Kotlin 支持

1,032 阅读7分钟

因最近一直在业余做Spring Framework 5.0 M4 文档的翻译工作(也就进度稍慢了),所以对5里面的各种比较关注,尤其是新东西,发现就拿来先翻译分享给大家了。

我们几个月前有介绍关于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 AriasKotlinPrimavera已经展示了我们可以带给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扩展包括:

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

Reactor Kotlin extensions

Reactor是Spring Framework 5.0的反应基础,并且有很好的机会你将使用它的MonoFlux和[StepVerifier] (StepVerifier (reactor-test 3.0.4.RELEASE)) 开发reactive Web应用程序时的API。

所以今天我们还通过新的reactor-kotlin项目在Reactor中引入Kotlin支持!它提供了扩展,能够通过写入foo.toMono()从任何类实例创建Mono实例,许多人喜欢Mono.just(foo)。它还支持例如使用stream.toFlux()从Java 8Stream实例创建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应用程序的一个具体例子,在github.com/mix-it/mixi…使用函数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不能可靠地使用这个插件,等待Kotlin1.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的脚本引擎来渲染模板。 Kotlin 1.1-M04提供了这样的支持,并允许渲染基于Kotlin的模板,有关详细信息,请参阅此提交

这使得出现了一些有趣的使用情况,如使用kotlinx.htmlDSL或简单的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 Boot2.0.0(SNAPSHOT)项目,可以自由测试Spring Framework 5.0 Kotlin支持并在这里或者在Kotlin Slack的“#spring”频道向我们发送您的反馈。你也可以 贡献你需要的Kotlin扩展;-)

翻译自:Introducing Kotlin support in Spring Framework 5.0

原来链接:一叶知秋

译者:知秋

[ 转载请保留原文出处、译者和译文链接。]