spring很早就支持kotlin,实际项目中大多数情况下都是java和kotlin混合编写,本文是一篇指引如何在springboot中使用kotlin与java混合开发,并且遇到的一些问题及解决方案。
本教程只演示maven下对kotlin的集成使用
1、声明要使用的kotlin的信息
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<kotlin.version>1.3.21</kotlin.version>
<kotlin.language.version>1.3</kotlin.language.version>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
<kotlin.compiler.languageVersion>${kotlin.language.version}</kotlin.compiler.languageVersion>
<kotlin.compiler.apiVersion>${kotlin.language.version}</kotlin.compiler.apiVersion>
<kotlin.compiler.jvmTarget>${java.version}</kotlin.compiler.jvmTarget>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
</properties>
这里有很多都不是必须的 具体参数意义请移步 kotlin官方maven工具文档
2、使用kotlin必要的maven包引入
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
</dependency>
3、增加maven编译插件
以下是我个人的使用配置,与kotlin官方的稍微有些不同
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<languageVersion>${kotlin.language.version}</languageVersion>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
遇到的问题
1、springboot使用maven编译、打包后启动都正常,但是在idea中启动项目报错
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: @Configuration class 'TestApplication' may not be final. Remove the final modifier to continue.
导致的原因是kotlin最终的class都是 final 修饰的,而spring中 @SpringBootApplication、@Configuration、@Bean等注解的class是可继承的,导致了一些问题, 具体细节可以参考这篇文章
解决方案
第一种:手动加上open关键字,麻烦而且在idea中默认是灰色,强迫症不好受。
第二种:修改工程配置文件。必须保证当前的配置是按上面的maven配置来的,
然后针对idea开发工具下的项目增加或修改.iml文件,下面是一个完整的.iml文件,可以参考此文件适当修改自己工程的.iml文件(修改前备份一下文件,错了还能还原)
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
<facet type="web" name="Web">
<configuration>
<webroots />
<sourceRoots>
<root url="file://$MODULE_DIR$/src/main/java" />
<root url="file://$MODULE_DIR$/src/main/resources" />
</sourceRoots>
</configuration>
</facet>
<facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="JVM 1.8" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-java-parameters" />
</compilerSettings>
<compilerArguments>
<option name="jvmTarget" value="1.8" />
<option name="languageVersion" value="1.3" />
<option name="apiVersion" value="1.3" />
<option name="pluginOptions">
<array>
<option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.stereotype.Component" />
<option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.transaction.annotation.Transactional" />
<option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.scheduling.annotation.Async" />
<option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.cache.annotation.Cacheable" />
<option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.boot.test.context.SpringBootTest" />
<option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.validation.annotation.Validated" />
</array>
</option>
<option name="pluginClasspaths">
<array>
<option value="$KOTLIN_BUNDLED$/lib/allopen-compiler-plugin.jar"/>
</array>
</option>
</compilerArguments>
</configuration>
</facet>
</component>
</module>
注意文件中没有以下代码块的加上
<option name="pluginClasspaths">
<array>
<option value="$KOTLIN_BUNDLED$/lib/allopen-compiler-plugin.jar"/>
</array>
</option>
然后maven清理下当前的编译文件,重新启动springboot项目,应该就能正常启动了。
2、声明的 javaBean无法直接按照kotlin的方式获取属性。
例如:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "min_user")
@DynamicUpdate
@DynamicInsert
@Accessors(chain = true)
public class MinUser implements Serializable {
@Id
@Column(name = "id",
columnDefinition = "bigint(20) COMMENT 'ID,自增'")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "openId",
columnDefinition = ("varchar(100) COMMENT 'openid'"), unique = true)
private String openId;
@Column(name = "session_key",
columnDefinition = ("varchar(255) COMMENT '会话密钥'"))
private String sessionKey;
@Column(name = "unionid",
columnDefinition = ("varchar(100) COMMENT '用户在开放平台的唯一标识符'"))
private String unionid;
}
使用kotlin代码进行赋值或者取值的时候会报错,无法找到属性。
例如以下代码:
val user= MinUser()
user.openId="123456"
解决方案
原因是kotlin无法访问私有的javabean对象资源 需要属性 private 改为 public,如果使用kotlin的方式声明javabean则没有此问题。但是由于使用了hibernate持久化方案,为了避免hibernate和spring-data-jpa与kotlin的不兼容,故javabean最好是使用java创建
3、lombok.extern.slf4j.Slf4j 注解在kotlin的class上无法使用。
解决方案
在class中声明 private val logger = LoggerFactory.getLogger(javaClass) 替换原有的@Slf4j方式
评论区