在Spring Framework 5.0中引入Kotlin支持
ValCason
8年前
<p>我们几个月前有介绍关于 Kotlin在start.spring.io上的支持 ,我们有一直在进行工作,以确保Spring和 Kotlin 在一起玩得很好。 Kotlin的一个关键优势是它提供了一个与用Java编写的库之间非常好的 <a href="/misc/goto?guid=4958988011971845413" rel="nofollow,noindex">互操作性</a> 。但是有更多的方法可以进一步,允许编写完全成熟的Kotlin代码,当开发您的下一个Spring应用程序。除了Spring Framework对Java 8的支持,Kotlin应用程序可以利用类似功能的Web或bean注册API,还有其他Kotlin专用功能,应该可以让你的生产力水平达到一个新的高度。</p> <p>这就是为什么我们在 Spring Framework 5.0 M4 中引入了一个专门的Kotlin支持,我想在这篇博客中总结的功能,旨在使您的开发人员体验无缝的在Spring中一起使用这些技术。你可以使用 <a href="/misc/goto?guid=4959734082812560210" rel="nofollow,noindex">这个链接</a> 在Spring Framework bug tracker中查找Kotlin的相关问题。</p> <h2>利用Kotlin可空信息(nullable information)</h2> <p>Spring最初基于来自 Raman Gupta 的社区贡献,现在利用 Kotlin null-safety support 以确定是否需要HTTP参数,而不必显式地定义 required 属性。 这意味着 @RequestParam name:String? 被视为不需要(not required), @RequestParam name:String 视为必需。 这也支持Spring消息 @Header 注解。</p> <p>以类似的方式,使用 @Autowired 或 @Inject 的Spring bean注入使用此信息来知道是否需要bean。 @Autowired lateinit var foo:Foo 意味着 Foo 类型的bean必须在应用程序上下文中注册,而 @Autowired lateinit var foo:Foo? 不会引发错误,如果这样的bean不存在。</p> <h2>RestTemplate和Functional Web API的扩展</h2> <p>Kotlin extensions 允许以非侵入方式扩展现有的API,提供了一个更好的替代实用程序类或在Kotlin特定类层次结构中添加Kotlin专用功能到Spring中。一些类似 Mario Arias 的 KotlinPrimavera 已经展示了我们可以带给Spring的各种Kotlin助手API,以允许编写更多的惯用代码。使用Spring Framework 5,我们集成了Spring框架中最有用和最受欢迎的扩展,并添加了新的扩展。</p> <p>例如, Kotlin reified type parameters 为JVM泛型类型擦除提供了一个解决方法,因此我们介绍了一些扩展,以利用此功能在可能的情况下提供更好的API。</p> <p>这允许为RestTemplate提供方便的API(感谢来自Netflix的 Jon Schneider 为此做出贡献)。例如,要在Java中检索“Foo”对象的列表,必须写:</p> <pre> <code class="language-kotlin">List<Foo> result = restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<List<Foo>>() { }).getBody(); </code></pre> <p>或者,如果你使用中间数组:</p> <pre> <code class="language-kotlin">List<Foo> result = Arrays.asList(restTemplate.getForObject(url, Foo[].class)); </code></pre> <p>而在Kotlin与Spring Framework 5扩展中,你将能够写:</p> <pre> <code class="language-kotlin">val result : List<Foo> = restTemplate.getForObject(url) </code></pre> <p>请注意,Kotlin扩展名是静态解析的,你必须导入它们。 在上面的示例中,您需要添加 import org.springframework.web.client.RestOperationsExtension.getForObject 才能使用它。 Kotlin扩展通常由IDE(如IntelliJ IDEA)(如静态导入)自动建议,但对于嵌套在容器 object 中的扩展,它仍然无效(您可以投票KT-15440),所以直到它被修复,你将不得不手动添加Spring Kotlin扩展导入。</p> <p>Spring Framework 5.0 M4中目前可用的“RestTemplate”或功能性Web API扩展包括:</p> <ul> <li><a href="/misc/goto?guid=4959734082893792931" rel="nofollow,noindex">RestOperationsExtension</a></li> <li><a href="/misc/goto?guid=4959734082974905484" rel="nofollow,noindex">ServerRequestExtension</a></li> <li><a href="/misc/goto?guid=4959734083060318365" rel="nofollow,noindex">BodyInsertersExtension</a></li> <li><a href="/misc/goto?guid=4959734083156540483" rel="nofollow,noindex">BodyExtractorsExtension</a></li> <li><a href="/misc/goto?guid=4959734083240374749" rel="nofollow,noindex">ClientResponseExtension</a></li> </ul> <p>这些扩展还提供了支持本地Kotlin KClass 的成员函数,允许你指定 Foo :: class 参数而不是 Foo :: class.java 。</p> <h2>Reactor Kotlin extensions</h2> <p>Reactor 是Spring Framework 5.0的反应基础,并且有很好的机会你将使用它的 Mono , Flux 和[StepVerifier] 开发reactive Web应用程序时的API。</p> <p>所以今天我们还通过新的 reactor-kotlin 项目在Reactor中引入Kotlin支持!它提供了扩展,能够通过写入 foo.toMono() 从任何类实例创建 Mono 实例,许多人喜欢 Mono.just(foo) 。它还支持例如使用 stream.toFlux() 从Java 8 Stream 实例创建 Flux 。还提供了 Iterable , CompletableFuture 和 Throwable 扩展以及基于KClass的Reactor API变体。</p> <p>这仍然是这个项目的早期,所以如果你想提供没有的功能,随时自由地 贡献 你自己的扩展。</p> <h2>Functional bean registration with Kotlin</h2> <p>Spring Framework 5.0引入了一种新的方式来注册bean,使用lambda作为XML或JavaConfig的替代,使用 @Configuration 和 @Bean 。 简而言之,它使得有可能注册bean与一个 Supplier lambda,充当一个 FactoryBean 。</p> <p>在Java中,你将会写如下的代码:</p> <pre> <code class="language-kotlin">AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.registerBean(Foo.class); context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class)) ); </code></pre> <p>而在Kotlin中,reified类型参数允许我们简单地写:</p> <pre> <code class="language-kotlin">val context = AnnotationConfigApplicationContext() context.registerBean(Foo::class) context.registerBean(Supplier { Bar(context.getBean(Foo::class)) }) </code></pre> <p>你可以看到Spring应用程序的一个具体例子,在 https://github.com/mix-it/mixit / 使用函数 web 和 bean注册 API。</p> <p>ApplicationContext 相关Kotlin可用扩展如下:</p> <ul> <li><a href="/misc/goto?guid=4959734083318372722" rel="nofollow,noindex">BeanFactoryExtension</a></li> <li><a href="/misc/goto?guid=4959734083403449381" rel="nofollow,noindex">ListableBeanFactoryExtension</a></li> <li><a href="/misc/goto?guid=4959734083485531866" rel="nofollow,noindex">GenericApplicationContextExtension</a></li> </ul> <h2>No need to declare your bean class as open anymore</h2> <p>直到现在,使用Kotlin构建Spring Boot应用程序时遇到的几个问题之一是需要在每个类上添加一个 open 关键字,并且使用CGLIB(如 @Configuration 类)来代替Spring bean的成员函数。 这个需求的根本原因来自于事实,在Kotlin, classes are final by default 。</p> <p>幸运的是,Kotlin 1.0.6现在提供了一个 kotlin-spring 插件,在默认情况下打开类和它们的成员函数,注解或元注解使用以下注解之一:</p> <ul> <li>@Component</li> <li>@Async</li> <li>@Transactional</li> <li>@Cacheable</li> </ul> <p>元注解支持意味着用 @Configuration , @Controller , @RestController , @Service 或 @Repository 注解的类会自动打开,因为这些注解是使用 @Component 进行的元注解。</p> <p>我们更新了 start.spring.io 默认启用它。 你可以看看 这个Kotlin 1.0.6博客帖子 了解更多详情,包括 新的 kotlin-jpa 和 kotlin-noarg 插件对Spring Data实体非常有用。</p> <h2>Kotlin based Gradle build configuration</h2> <p>回到5月,Gradle 宣布 ,他们将支持在Groovy之外的Kotlin中编写构建和配置文件。这使得可以在IDE中具有完全自动完成和验证,因为这些文件是常规静态类型的Kotlin脚本文件。这很可能成为基于Kotlin的项目的自然选择,但这也对Java项目也很有价值。</p> <p>自5月以来, gradle-script-kotlin 项目不断发展,现在可以使用2个警告:</p> <ul> <li>你需要Kotlin 1.1-EAP IDEA插件来获得自动完成(但如果你使用 kotlin-spring 插件,因为 1.1-M04 不能可靠地使用这个插件,等待Kotlin 1.1-M05 )</li> <li>文档不完整,但Gradle团队对Kotlin Slack的#gradle频道非常有帮助。</li> </ul> <p>两个 spring-boot-kotlin-demo 项目使用这种基于Kotlin的Gradle构建,可以随意看看。我们)在start.spring.io 讨论 上添加了这样的支持。</p> <h2>Kotlin Script based templates</h2> <p>从4.3版本开始,Spring Framework提供了一个 ScriptTemplateView 使用支持 JSR-223 的脚本引擎来渲染模板。 K</p> <p>这使得出现了一些有趣的使用情况,如使用 kotlinx.html DSL或简单的Kotlin multiline(多线)’String’插值,编写类型安全模板,例如此 kotlin -script-templating 项目。 这可以允许您在IDE中编写具有完全自动完成功能和重构支持的这类模板:</p> <pre> <code class="language-kotlin">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")} """ </code></pre> <p>这个功能仍在进行中,但我正在与Kotlin团队合作,暂时使其准备好对Spring Framework 5.0 GA上的嵌套模板和i18n在MVC和Reactive两方面的支持。</p> <h2>结语</h2> <p>我使用Kotlin编写Spring Boot应用程序越多,我觉得这两种技术有着共同的目标,允许您使用表达性,简短和可读的代码来更高效地编写应用程序,而Spring Framework 5 Kotlin支持将这些技术以更加自然,简单和强大的方式来展现给我们。</p> <p>Kotlin可以用来编写 基于注解的Spring Boot应用程序 ,但作为一种新的 functional and reactive applications 也将是一种很好的尝试,Spring Framework 5.0将会启用。</p> <p>Kotlin团队做了一个伟大的工作,修复几乎所有的bug点,我们报告,所以非常感谢他们。即将到来的Kotlin 1.1版本预计也修复 KT-11235 ,以允许指定数组注解标记单个属性值,无须使用 arrayOf() 。你将面临的主要问题可能是 KT-14984 ,它将需要明确指定lambda类型(如 Supplier {} 或 HandlerFunction {} )其中只需指定 {} 应该就足够了。</p> <p>通过转到 start.spring.io 并生成一个Spring Boot 2.0.0(SNAPSHOT) 项目,可以自由测试Spring Framework 5.0 Kotlin支持并在这里或者在 Kotlin Slack 的“#spring”频道向我们发送您的反馈。你也可以 <a href="/misc/goto?guid=4959734083576247738" rel="nofollow,noindex">贡献</a> 你需要的Kotlin扩展;-)</p> <p> </p> <p> </p> <p>来自:https://muyinchen.github.io/2017/01/09/在Spring Framework 5.0中引入Kotlin支持/</p> <p> </p>