随着Kotlin语言的普及,它更常用于Spring Boot来构建后端服务。从版本5开始,Spring Framework引入了对Kotlin的一流支持。在本文中,我将向您展示使用Kotlin和Spring Boot 2进行微服务构建的示例。我将描述Spring Boot的一些有趣功能,在构建基于REST的后端微服务时,可以将其视为一组良好实践。
1.配置和依赖
要在Maven项目使用Kotlin你必须包括插件kotlin-maven-plugin,并且/src/main/kotlin,/src/test/kotlin目录生成配置。我们还将-Xjsr305编译器标志设置为strict。此选项负责检查对JSR-305注释的支持(例如@NotNull注释)。
<build> <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory> <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory> <plugins> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <configuration> <args> <arg>-Xjsr305=strict</arg> </args> <compilerPlugins> <plugin>spring</plugin> </compilerPlugins> </configuration> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-allopen</artifactId> <version>${kotlin.version}</version> </dependency> </dependencies> </plugin> </plugins> </build>
我们还应该包括一些像kotlin-stdlib-jdk8和的核心Kotlin库kotlin-reflect。默认情况下,我们可以在start.spring.io上配置Kotlin项目,生成pom.xml。对于基于REST的应用程序,您还需要用于JSON序列化/反序列化的Jackson库。当然,我们必须包括用于Web应用程序的Spring启动器以及负责提供管理端点的Actuator。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</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
我们使用最新的稳定版Spring Boot和Kotlin 1.2.71
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> </parent> <properties> <java.version>1.8</java.version> <kotlin.version>1.2.71</kotlin.version> </properties>
2.架构应用
让我们从基础开始。如果您熟悉Spring Boot和Java,最大的区别在于主类声明。您将runApplication在Spring Boot应用程序类之外调用方法。主要类与Java中的相同,使用注释@SpringBootApplication。
@SpringBootApplication <b>class</b> SampleSpringKotlinMicroserviceApplication fun main(args: Array<String>) { runApplication<SampleSpringKotlinMicroserviceApplication>(*args) }
我们的示例应用程序非常简单。它公开了一些REST端点,为模型对象提供CRUD操作。即使在这个代码控制器实现的代码片段中,您也可以看到一些不错的Kotlin功能。我们可以使用缩短的函数声明和推断的返回类型。注释@PathVariable不需要任何参数。输入参数名称被视为与变量名称相同。当然,我们使用与Java相同的注释。在Kotlin中,必须在构造函数中初始化声明为非null类型的每个属性。所以,如果你使用依赖注入初始化它,它必须声明为lateinit。这些在PersonController中实施:
@RestController @RequestMapping(<font>"/persons"</font><font>) <b>class</b> PersonController { @Autowired lateinit <b>var</b> repository: PersonRepository @GetMapping(</font><font>"/{id}"</font><font>) fun findById(@PathVariable id: Int): Person? = repository.findById(id) @GetMapping fun findAll(): List<Person> = repository.findAll() @PostMapping fun add(@RequestBody person: Person): Person = repository.save(person) @PutMapping fun update(@RequestBody person: Person): Person = repository.update(person) @DeleteMapping(</font><font>"/{id}"</font><font>) fun remove(@PathVariable id: Int): Boolean = repository.removeById(id) } </font>
Kotlin自动为声明为的类属性生成getter和setter var。此外,如果你声明模型作为数据类它产生equals,hashCode和toString方法。我们的模型类的声明Person非常简洁,如下所示。
data <b>class</b> Person(<b>var</b> id: Int?, <b>var</b> name: String, <b>var</b> age: Int, <b>var</b> gender: Gender)
我已经实现了自己的内存存储库类。我使用Kotlin扩展来操作元素列表。这个内置的Kotlin功能类似于Java流,不同之处在于您不必在Collection和之间执行任何转换Stream。
@Repository <b>class</b> PersonRepository { val persons: MutableList<Person> = ArrayList() fun findById(id: Int): Person? { <b>return</b> persons.singleOrNull { it.id == id } } fun findAll(): List<Person> { <b>return</b> persons } fun save(person: Person): Person { person.id = (persons.maxBy { it.id!! }?.id ?: 0) + 1 persons.add(person) <b>return</b> person } fun update(person: Person): Person { val index = persons.indexOfFirst { it.id == person.id } <b>if</b> (index >= 0) { persons[index] = person } <b>return</b> person } fun removeById(id: Int): Boolean { <b>return</b> persons.removeIf { it.id == id } } }
3. 启用执行器端点
由于我们已将Spring Boot starter与Actuator一起包含在应用程序代码中,因此我们可以利用其生产就绪功能。Spring Boot Actuator为您提供了非常强大的工具来监控和管理您的应用程序。您可以提供高级健康检查,信息端点或将指标发送到众多监控系统,如InfluxDB。在包含Actuator工件之后,我们唯一要做的就是通过HTTP为我们的应用程序启用其所有端点。
management.endpoints.web.exposure.include: '*'
我们可以自定义Actuator端点,以提供有关我们应用的更多详细信息。一个好的做法是将有关版本和git提交的信息公开给info端点。像往常一样,Spring Boot为这些功能提供了自动配置,因此我们唯一需要做的就是包含一些Maven插件来构建配置pom.xml。build-info设定的目标是spring-boot-maven-plugin强制它生成包含有关版本的基本信息的属性文件。该文件位于目录中META-INF/build-info.properties。插件git-commit-id-plugin将git.properties在根目录中生成文件。
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>build-info</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>pl.project13.maven</groupId> <artifactId>git-commit-id-plugin</artifactId> <configuration> <failOnNoGitDirectory>false</failOnNoGitDirectory> </configuration> </plugin>
现在,您应该使用mvn clean install命令构建应用程序,然后运行它。
$ java -jar target/sample-spring-kotlin-microservice-1.0-SNAPSHOT.jar
该info端点是在地址 http://localhost:8080/actuator/info . 它为我们揭示了所有有趣的信息。
{ <font>"git"</font><font>:{ </font><font>"commit"</font><font>:{ </font><font>"time"</font><font>:</font><font>"2019-01-14T16:20:31Z"</font><font>, </font><font>"id"</font><font>:</font><font>"f7cb437"</font><font> }, </font><font>"branch"</font><font>:</font><font>"master"</font><font> }, </font><font>"build"</font><font>:{ </font><font>"version"</font><font>:</font><font>"1.0-SNAPSHOT"</font><font>, </font><font>"artifact"</font><font>:</font><font>"sample-spring-kotlin-microservice"</font><font>, </font><font>"name"</font><font>:</font><font>"sample-spring-kotlin-microservice"</font><font>, </font><font>"group"</font><font>:</font><font>"pl.piomin.services"</font><font>, </font><font>"time"</font><font>:</font><font>"2019-01-15T09:18:48.836Z"</font><font> } } </font>
4.启用API文档
构建信息和git属性可以很容易地注入到应用程序代码中。在某些情况下它可能很有用。其中一种情况是您已启用自动生成的API文档。最常用的工具是Swagger。您可以使用SpringFox Swagger项目轻松地将Swagger2与Spring Boot集成。首先,您需要包含以下依赖项pom.xml。
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>
然后,您应该通过使用注释配置类来启用Swagger @EnableSwagger2。所需的信息是在BuildProperties和GitProperties,我们只需将它们注入到Swagger配置类中,如下所示。我们将它们设置为可选,以防止应用程序启动失败,以防它们不存在于类路径中。
@Configuration @EnableSwagger2 <b>class</b> SwaggerConfig { @Autowired lateinit <b>var</b> build: Optional<BuildProperties> @Autowired lateinit <b>var</b> git: Optional<GitProperties> @Bean fun api(): Docket { <b>var</b> version = <font>"1.0"</font><font> <b>if</b> (build.isPresent && git.isPresent) { <b>var</b> buildInfo = build.get() <b>var</b> gitInfo = git.get() version = </font><font>"${buildInfo.version}-${gitInfo.shortCommitId}-${gitInfo.branch}"</font><font> } <b>return</b> Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo(version)) .select() .apis(RequestHandlerSelectors.any()) .paths{ it.equals(</font><font>"/persons"</font><font>)} .build() .useDefaultResponseMessages(false) .forCodeGeneration(<b>true</b>) } @Bean fun uiConfig(): UiConfiguration { <b>return</b> UiConfiguration(java.lang.Boolean.TRUE, java.lang.Boolean.FALSE, 1, 1, ModelRendering.MODEL, java.lang.Boolean.FALSE, DocExpansion.LIST, java.lang.Boolean.FALSE, <b>null</b>, OperationsSorter.ALPHA, java.lang.Boolean.FALSE, TagsSorter.ALPHA, UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS, <b>null</b>) } <b>private</b> fun apiInfo(version: String): ApiInfo { <b>return</b> ApiInfoBuilder() .title(</font><font>"API - Person Service"</font><font>) .description(</font><font>"Persons Management"</font><font>) .version(version) .build() } } </font>
文档在/swagger-ui.html路径下可用。除API文档外,还显示有关应用程序版本,git commit id和分支名称的完整信息。
5.选择您的应用服务器
Spring Boot Web可以在三个不同的嵌入式服务器上运行:Tomcat,Jetty或Undertow。默认情况下,它使用Tomcat。要更改默认服务器,您只需要包含合适的Spring Boot启动器并排除spring-boot-starter-tomcat。良好的做法可能是在应用程序构建期间启用服务器之间的切换。您可以通过声明Maven配置文件来实现它,如下所示。
<profiles> <profile> <id>tomcat</id> <activation> <activeByDefault><b>true</b></activeByDefault> </activation> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </profile> <profile> <id>jetty</id> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> </dependencies> </profile> <profile> <id>undertow</id> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> </dependencies> </profile> </profiles>
现在,如果您想为应用程序启用除Tomcat之外的其他服务器,则应在Maven构建期间激活相应的配置文件。
$ mvn clean install -Pjetty
示例应用程序源代码在GitHub的存储库 https://github.com/piomin/sample-spring-kotlin-microservice.git