WebFlux有两种编程模型
- 传统的 Annotated Controllers 注释控制器
- 轻量的 Functional Endpoints 函数式后端
Annotated Controllers 注释控制器 使用方式就是传统的MVC那套,多了一个@RequestBody注释。允许返回Flux,Mono类型,Kotlin可以使用挂起函数(suspend)和返回类型特有的返回类型Flow或deferred。
@GetMapping("/suspend")
suspend fun suspendingEndpoint(): String {
delay(10)
return "suspend"
}
@GetMapping("/flow")
fun flowEndpoint() = flow {
delay(10)
emit("flow")
delay(2000)
emit("flow")
}
@GetMapping("/deferred")
suspend fun deferredEndpoint() = withContext(Dispatchers.Default) {
delay(10)
"deferred"
}
@GetMapping("await")
suspend fun await() = coroutineScope {
measureTimeMillis {
val one: Deferred<Int> = async (start = CoroutineStart.LAZY){
delay(2000)
1+1
}
val two: Deferred<Int> = async (start = CoroutineStart.LAZY){
delay(1000)
2+2
}
one.await() + two.await()
}
}
Functional Endpoints 函数式后端允许不启动整个spring来启动服务端。启动非常快,占用内存少。适用小型项目,项目太多,路由表会变得非常复杂。
class NanoApplication {}
fun main() {
val httpHandler = RouterFunctions.toHttpHandler(routes())
val reactorHttpHandler = ReactorHttpHandlerAdapter(httpHandler)
HttpServer.create()
.port(8080)
.handle(reactorHttpHandler)
.bind()
.flatMap(DisposableChannel::onDispose)
.block()
}
fun routes():RouterFunction<ServerResponse> =
route(GET("/connection"),{
it.bodyToMono(String::class.java).log().flatMap { ServerResponse.ok().build()}
})
传统的Annotated Controllers 基于注解回调路由,可以使用 @Validated 做验证,Functional Endpoints做验证需要自己写实现。生产环境验证时必须的,做高并发项目还是选择Functional Endpoints,简单又需要一点严谨的应用可以使用Annotated Controllers方式。只是非常简单架一个服务端可以采用上方的,秒级启动方式。还有一种是下方官方示例的方式,启动Spring扫描配bean。
以后再补充…
spring.io官网的2个KotlinDSL路由示例
a WebFlux.fn RouterFunction with a Coroutines router Kotlin DSL.
/**
* @author Sebastien Deleuze
**/
@Configuration
class RouterConfiguration {
@Bean
fun mainRouter(userHandler: UserHandler) = coRouter {
accept(TEXT_HTML).nest {
(GET("/user/") or GET("/users/")).invoke(userHandler::findAllView)
GET("/users/{login}", userHandler::findViewById)
}
accept(APPLICATION_JSON).nest {
(GET("/api/user/") or GET("/api/users/")).invoke(userHandler::findAll)
POST("/api/users/", userHandler::create)
}
}
}
a WebFlux.fn RouterFunction with a Reactive router Kotlin DSL.
@Configuration
class RouterConfiguration {
@Bean
fun mainRouter(userHandler: UserHandler) = router {
accept(TEXT_HTML).nest {
GET("/") { ok().render("index") }
GET("/sse") { ok().render("sse") }
GET("/users", userHandler::findAllView)
}
"/api".nest {
accept(APPLICATION_JSON).nest {
GET("/users", userHandler::findAll)
}
accept(TEXT_EVENT_STREAM).nest {
GET("/users", userHandler::stream)
}
}
resources("/**", ClassPathResource("static/"))
}
}