概述
kotlin语言作为后起之秀拥有很多下一代语言的新特性,个人使用起来觉得相较于java,更安全、更简洁。但是项目组中的其他同事仍未接触过该语言,故而新项目并不能完全使用kotlin。同时,项目组也偏向于使用maven来做构建。
kotlin与java有互操作性,两者可以在项目中共存,本文主要介绍用maven集成两者的实现方式。
依赖
- springboot 2.5.5
- maven 3.8.5
- kotlin 1.5.31
- java 1.8
项目demo代码
gitee by peaksong
github by peaksong
重要插件
maven在打包构建有自己的一套生命周期,同时支持第三方以插件的方式,实现丰富的特性和功能。本次主要使用的插件分别是kotlin-maven-plugin
、spring-boot-maven-plugin
和maven-compiler-plugin
。
kotlin-maven-plugin
主要用来处理kotlin代码maven-compiler-plugin
主要涉及对maven原有构建生命周期阶段和目标的修改spring-boot-maven-plugin
主要用来构建一个可运行的jar包
在构建中会遇到各种问题,分别使用添加插件或修改插件配置的方式来解决。
kotlin-maven-plugin
下面简单地介绍各项配置的意义。
- -Xjsr305=strict
尽管Java不支持在其类型系统中表示null安全,但是Spring Framework通过在org.springframework.lang
包中声明的对工具友好的注释提供了整个Spring Framework API的空安全。默认情况下,在Kotlin中使用的Java API中的类型会被识别为放松了空检查的平台类型。
Kotlin对 JSR 305 annotations 的支持为Kotlin开发人员提供了整个Spring Framework API的null安全性,其优点是在编译时处理与null相关的问题。
- all-open
官网解析 https://kotlinlang.org/docs/all-open-plugin.html#maven 因为kotlin中所有的类默认都是不可继承,spring框架的代理就不好使了。所以kotlin代码里会满满的open。这个插件可以省掉这些open,为指定注解注解的类在编译时添加open。
如果使用了jpa, 一般会添加如下的option
<option>all-open:annotation=javax.persistence.Entity</option>
<option>all-open:annotation=javax.persistence.Embeddable</option>
<option>all-open:annotation=javax.persistence.MappedSuperclass</option>
如果代码中还有自定义的注解用于大多数类,也可以一并加入该option。
-
spring 在all-open的官网解析中也能看到,spring插件依赖于all-open。其功能是指定一些spring常用注解来添加open。
该插件指定了以下注解:@Component
、@Async
、@Transactional
、@Cacheable
以及@SpringBootTest
。
同时,由于元注解的支持,标注有@Configuration
、@Controller
、@RestController
、@Service
或者@Repository
的类会自动打开,因为这些注解标注有元注解@Component
。 -
no-arg
官网解析 https://kotlinlang.org/docs/no-arg-plugin.html#maven
与all-open类似,主要是用来添加无参构造方法,这在jpa中使用data class定义entity的场景中十分有效。 -
jpa 与 kotlin-spring 插件类似,kotlin-jpa 是在 no-arg 之上的一层包装。该插件自动指定了
@Entity
、@Embeddable
与@MappedSuperclass
这几个 无参 注解。 -
lombok
官网解析 https://kotlinlang.org/docs/lombok.html
添加对lombok的支持,比如在kotlin使用lombok注解的类。
本文的实现没有使用kapt。读者可以仿照以下项目,自行选择合适的解决方案。 github.com/kotlin-hand…
同时,不忘提醒一句,要检查插件是否安装成功,只要安装成功就一定不会有问题。笔者在实践时,阿里云仓库没有同步到中央仓库1.5.31版本的插件,导致了一些反复。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.peaksong</groupId>
<artifactId>boot-kotlin-maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>boot-kotlin-maven</name>
<description>boot-kotlin-maven</description>
<properties>
<java.version>1.8</java.version>
<kotlin.version>1.5.31</kotlin.version>
<springboot.verion>2.5.5</springboot.verion>
<lombok.version>1.18.20</lombok.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.sourceEncoding>UTF-8</project.reporting.sourceEncoding>
<maven.compile.source>1.8</maven.compile.source>
<maven.compile.target>1.8</maven.compile.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
<plugin>lombok</plugin>
<!-- <plugin>jpa</plugin>-->
<plugin>all-open</plugin>
<plugin>no-arg</plugin>
</compilerPlugins>
<pluginOptions>
<!-- <option>all-open:annotation=javax.persistence.Entity</option>-->
<!-- <option>all-open:annotation=javax.persistence.Embeddable</option>-->
<!-- <option>all-open:annotation=javax.persistence.MappedSuperclass</option>-->
<!-- <pluginOption>no-arg:annotation=</pluginOption>-->
<!-- <pluginOption>all-open:annotation=</pluginOption>-->
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-lombok</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/java</sourceDir>
<sourceDir>src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/test/java</sourceDir>
<sourceDir>src/test/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${maven.compile.source}</source>
<target>${maven.compile.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<!-- <annotationProcessorPaths>-->
<!-- <path>-->
<!-- <groupId>org.projectlombok</groupId>-->
<!-- <artifactId>lombok</artifactId>-->
<!-- <veersion>${lombok.version}</veersion>-->
<!-- </path>-->
<!-- </annotationProcessorPaths>-->
<!-- <compilerArgs>-->
<!-- <arg>-parameters</arg>-->
<!-- </compilerArgs>-->
</configuration>
<executions>
<!-- 替换 default-compile, 因为它会被 maven 特别处理 -->
<!-- 去除会导致java中引用kotlin代码报错 找不到包或者符号 -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- 替换 default-testCompile, 因为它会被 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>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.verion}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>