尝试在Docker中运行Kotlin + Spring Boot + WebFlux
简要描述
这次我想挑战一下,在标题所述的情况下,使用Kotlin编写Spring Boot + WebFlux,并在Docker上运行。
组成
使用Kotlin + Spring Boot + WebFlux创建API,并使其在Docker上运行。
创建项目
我們這次將使用IntelliJ來創建項目。



在这些步骤之后,我会创建一个项目。(最开始可能会花费一些时间用于下载依赖关系等)
我自己尝试的时候,构建成功了而且没有出现任何问题,但如果遇到了困难,你可以参考下面的Gradle信息mm。
buildscript {
ext {
kotlinVersion = '1.2.51'
springBootVersion = '2.0.4.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
}
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.darmaso.spring'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-data-redis-reactive')
compile('org.springframework.boot:spring-boot-starter-thymeleaf')
//compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-webflux')
compile('com.fasterxml.jackson.module:jackson-module-kotlin')
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
runtime('org.springframework.boot:spring-boot-devtools')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('io.projectreactor:reactor-test')
}
直接执行而不加思考,并且如果输出了如下日志,就表示OK。
・・・Started KotlinwebfluxApplicationKt in 8.127 seconds (JVM running for 10.728)

目前的情况是,因为没有对路径进行处理,所以出现这种显示是没有问题的。
尝试使用WebFlux。
首先,为了快速创建API,我参考了WebFlux和Kotlin的响应式Web,在其中实现了一个返回用户列表的API。
以下是按照上述链接实施的示例。简要说明将在下文中提供。
路由
我会设置哪个路径执行哪个处理程序。
@Configuration
class Router(private val demoHandler: DemoHandler, private val userHandler: UserHandler) {
@Bean
fun apiRouter() = router {
accept(MediaType.APPLICATION_JSON_UTF8).nest {
GET("/v1/demo", demoHandler::getDemo)
GET("/v1/users", userHandler::findAll)
}
accept(MediaType.TEXT_EVENT_STREAM).nest {
GET("/stream/users", userHandler::streamOneSec)
}
}
}
在上面的例子中,它指的是设置对每个路径的请求为 application/json。特别之处在于第二个 accept 支持流式格式。
操作员
下面是userHandler的实现示例(完全是样本的拷贝)。
@Component
class UserHandler {
private val users = Flux.just(
User("1", "tarou", "1999-09-09"),
User("2", "hanako", "2002-02-02"),
User("3", "tonkichi", "1988-08-08")
)
private val streamingUsers = Flux
.zip(Flux.interval(Duration.ofSeconds(1)), users.repeat())
.map { it.t2 }
fun findAll(req: ServerRequest): Mono<ServerResponse> {
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8)
.body(users, User::class.java)
}
fun streamOneSec(req: ServerRequest) = ServerResponse.ok()
.bodyToServerSentEvents(streamingUsers)
}
绊倒的地方
我只需要一种选择,以下是对原文的汉语翻译:
只剩下尝试执行了,但是我会在此提到一点困扰的地方。
在build.gradle中引入了spring-boot-starter-web,
在应用程序启动时,Tomcat会启动,但无法进行预期的映射模式><
为了期望在webflux方面启动netty,我尝试将相应部分注释掉了。
但是,我记得读过一篇文章,说是应该在application.yaml等文件中进行设置?
但是我忘记在哪里写了。。。如果有人知道,请告诉我mm
执行结果
$ curl -H "accept: application/json" http://localhost:8080/v1/users
[
{"id":"1","name":"tarou","birth":"1999-09-09"},
{"id":"2","name":"hanako","birth":"2002-02-02"},
{"id":"3","name":"tonkichi","birth":"1988-08-08"}
]
$ curl -H "accept: application/json" http://localhost:8080/v1/demo
{"message":"hello kotlin"}
$ curl -H "accept: text/event-stream" http://localhost:8080/stream/users
data:{"id":"1","name":"tarou","birth":"1999-09-09"}
data:{"id":"2","name":"hanako","birth":"2002-02-02"}
data:{"id":"3","name":"tonkichi","birth":"1988-08-08"}
data:{"id":"1","name":"tarou","birth":"1999-09-09"}
data:{"id":"2","name":"hanako","birth":"2002-02-02"}
data:{"id":"3","name":"tonkichi","birth":"1988-08-08"}
data:{"id":"1","name":"tarou","birth":"1999-09-09"}
顺便说一下
我在上述的build.gradle中注释掉了spring-boot-starter-web,但是我仍然可以正常显示使用@Controller的HTML页面(只显示静态页面)。
@Controller
class IndexController {
@RequestMapping("/")
fun index(): String {
return "index"
}
}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Kotlin, Spring Boot2, WebFlux</title>
</head>
<body>
<p>Hello! Kotlin, Sprint Boot2, WebFlux</p>
</body>
</html>
运行结果如下所示
$ curl http://localhost:8080/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Kotlin, Spring Boot2, WebFlux</title>
</head>
<body>
<p>Hello! Kotlin, Sprint Boot2, WebFlux</p>
</body>
</html>
运行在Docker上
参考GCP的《在Google Kubernetes Engine上运行Kotlin Spring Boot应用程序》,尝试在Docker上运行。
Dockerfile的翻译为:镜像文件
直接使用上述样本
FROM openjdk:8-jdk-alpine
VOLUME /tmp
RUN mkdir /work
COPY . /work
WORKDIR /work
RUN /work/gradlew build
RUN mv /work/build/libs/*.jar /work/app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/work/app.jar"]
使用这个 Dockerfile 进行构建试试看。
$ docker build --no-cache -t demo .
Sending build context to Docker daemon 430.6kB
Step 1/8 : FROM openjdk:8-jdk-alpine
8-jdk-alpine: Pulling from library/openjdk
4fe2ade4980c: Pull complete
6fc58a8d4ae4: Pull complete
fe815adf554b: Pull complete
Digest: sha256:a2d7b02891b158d01523e26ad069d40d5eb2c14d6943cf4df969b097acaa77d3
Status: Downloaded newer image for openjdk:8-jdk-alpine
・・・・<<省略>>・・・・・
BUILD SUCCESSFUL in 3m 11s
6 actionable tasks: 6 executed
Removing intermediate container d931cb7f17f1
---> 51321afaedb9
Step 7/8 : RUN mv /work/build/libs/*.jar /work/app.jar
---> Running in 730bad53d9e7
Removing intermediate container 730bad53d9e7
---> 65a15aec971d
Step 8/8 : ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/work/app.jar"]
---> Running in bd139be8b399
Removing intermediate container bd139be8b399
---> d388bccfcf18
Successfully built d388bccfcf18
Successfully tagged demo:latest
由于构建成功,最后进行执行并确认其运行状态。
$ docker run -it --rm -p 8080:8080 demo
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.4.RELEASE)
・・・・・<<省略>>・・・・・
〜: Started HttpServer on /0.0.0.0:8080
〜: Netty started on port(s): 8080
〜: Started KotlinwebfluxApplicationKt in 7.599 seconds (JVM running for 8.422)
如果出现像上面那样的日志,并且获得与之前的”执行结果”相同的结果,那就可以了。
之后,可以使用Command + C或其他方式停止Docker(由于指定了–rm,在自动销毁容器时)。
如果您将它容器化,然后将其放在您喜欢的平台(如AWS、GCP、Azure等)上,应该会很不错。
我以后想做的事情
与Redis的连接
-
- せっかくWebFluxを使うので、Non-BlockingのNoSQLと接続してみるために、Redisを利用
-
- ローカル環境で開発するために、docker-composeでredisを動かす
- クラウド環境で接続するときは、接続先を変えるなど
CI/CD 在 AWS 上
-
- GithubにPushしたら、テストコードの実行とビルドまでが自動で動くようにする
- CIが完了すると、特定の環境(Fargateなど)にデプロイされるようにする
请提供更多上下文信息才能准确地回答您的问题。
-
- beta-yumatsud/springboot-study
-
- Reactive web services using Kotlin and Spring Boot 2
- Run a Kotlin Spring Boot application on Google Kubernetes Engine