Spring 与 Kotlin 兼容性注意事项
Kotlin与Java百分百互操作,顺理成章,Spring开发也可以用Kotlin。可以享受到Kotlin的简洁语法。二者结合的大部分特点,在尝试之后都能体会。本文列举一些实际开发中最容易遇到的问题。
关于POJO
DTO、VO、BO、MyBatis的Entity、Spring配置文件对应的PropertiesBean,各种Bean的组装与传输。直觉告诉我们,最好定义成data class,属性最好是val,最好是不可空,但不可一概而论,需按情况分析。
与前端交互的Bean:由于需要在前后端进行传输,需要设置为var的可空类型,且需要有一个不带任何参数的构造方法,有几点原因
var:以@RequestBody为例,Spring框架会先创建传输对象,再进行赋值
可空:无法预测前端输入是否为空,且Spring Validate是先构建对象、为属性赋值、再进行验证,即时我们以@NotNull注释了,还是可能在赋值时报不可空的类型赋值错误,而不是@NotNull引起的验证错误
不带参的构造方法:构建空对象 - 属性赋值,是Spring框架内部的常规操作,这也广泛存在于Java的其它三方库,因为Java默认存在无参构造,但Kotlin没有,需要显式构建。这又有两种方法
所有属性写构造方法,但都是可控类型,且赋予了默认值null
1
2
3
4
5data class AppleLoginReq(
var identityToken: String? = null
)真无参构造
1
2
3
4
5class AppleLoginReq {
var identityToken: String? = null
}
业务内传输Bean:业务内可控,依据实际需要定义为data class + val属性 + 不可空或可空类型,构造方法如实即可
配置对应的Bean:Spring手册中特别提到,可以用data class + lateinit var的形式,不过还是得有无参构造方法
ORM的Table对应的Bean:虽然数据表是我们定义的,但将ORM对应的Bean属性的可空性和数据表字段的可空性对齐是一件非常繁琐的事。且涉及到日后维护问题,因此建议和前端交互Bean一样,var + 可空类型 + 无参构造方法
val和var
项目中,纯业务代码能够依照Kotlin建议尽量使用val,但在与框架交互的代码中,使用var经常是唯一选择,主要原因是框架常常采用先创建对象再赋值的形式进行初始化。且赋值可能使用属性字段,也可能使用setter方法,因此,还得是var。常见的注入声明也变成了如下形式
1 |
|
属性复制
字段太多怎么办,属性赋值方法挺不错。考虑到原理,要求源对象的属性必须有getter方法,且,目标对象的属性必须有setter方法,否则复制不会成功
1 | /** |
默认final的问题
Spring中用到动态代理或CGLib,要求类可继承,而Kotlin具有默认final的原则,常见方式是手动标注该类为open,使用open关键字。Kotlin提供了一个插件,用注解替代open。我们可以将已有注解放在这里,就啥也不必加了。
1 | allOpen { |
Kotlin的Spring插件
针对Spring的特殊要求,Kotlin提供了五个插件:三个已成熟、两个实验中
MyBatis Plus的Kotlin支持
注意MyBatis Plus支持的kotlin DSL的使用,会简单很多,不要再手动创建QueryWrapper了、不要再手动指定字段名了
1 |
|
这一点放在这里有点突兀,但体现了其重要性,值得强调
总结
Spring切换Kotlin遇到的最大问题还是框架本身大量使用反射、动态代理等技术带来的,究其原因,它是依据Java特性开发的框架。这就导致并不能在Spring中非常完美地使用Kotlin的各种特性,只能发挥Kotlin 90%的简介特性。不那么Kotlin的点,总结下就是
- 经常使用var
- 经常使用平台类型
- 出于对值的未知不得不使用可空类型
- 必须有的无参构造、class的open关键字