spring boot與ktor整合的實(shí)現(xiàn)方法
背景
在用了一陣子 Ktor 之后,深感基于協(xié)程的方便,但是公司的主要技術(shù)棧是 SpringBoot,雖然已經(jīng)整合了 Kotlin,但是如果有 Ktor 加持則會(huì)更加的方便。因此作了一番研究后,也完全可以實(shí)現(xiàn)這樣的整合了。
建立一個(gè) starter
首先新建一個(gè) Kotlin 項(xiàng)目,在其 build.gradle 內(nèi)加入對(duì) SpringBoot 和 Ktor 的依賴,并同時(shí)加入對(duì)打?yàn)?jar 包的代碼:
dependencies {
implementation "org.springframework.boot:spring-boot-starter-aop:${springBootVersion}"
implementation "io.ktor:ktor-jackson:${ktorVersion}"
compile "io.ktor:ktor-server-netty:${ktorVersion}"
compile "io.ktor:ktor-html-builder:${ktorVersion}"
testImplementation "org.springframework.boot:spring-boot-starter-test:${springBootVersion}"
testCompile "io.ktor:ktor-client-apache:${ktorVersion}"
testCompile "io.ktor:ktor-server-test-host:${ktorVersion}"
}
jar {
from {
configurations.runtime.collect { zipTree(it) }
}
}
task sourceJar(type: Jar) {
from sourceSets.main.allSource
classifier 'sources'
}
對(duì)于 SpringBoot 來說,工程內(nèi)的 Configuration,Controller,Module 都是必要的,因此也需要 Ktor 可以符合這些約定俗成的組件。
那么就簡(jiǎn)單來實(shí)現(xiàn)一下吧,首先實(shí)現(xiàn) Controller 的代碼,我們只需要讓 SpringBoot 的 Controller 支持 Ktor 的路由寫法就可以了:
interface KRouter {
fun Routing.route()
}
@ContextDsl
fun Routing.request(
path: String,
body: PipelineInterceptor<Unit, ApplicationCall>
) = route(path) { handle(body) }
然后實(shí)現(xiàn)基礎(chǔ)的 Module:
interface KModule {
fun Application.defaultRegister(
useCompress: Boolean = false,
redirectHttps: Boolean = false,
headers: String = ""
) {
install(ContentNegotiation) { jackson { } }
install(PartialContent) { maxRangeCount = 10 }
if (useCompress) {
install(Compression) {
gzip { priority = 1.0 }
deflate {
priority = 10.0
minimumSize(1024)
}
}
}
if (redirectHttps) {
install(HttpsRedirect) {
sslPort = URLProtocol.HTTPS.defaultPort
permanentRedirect = true
}
}
if (headers != "") {
install(DefaultHeaders) {
headers.toCookieMap().forEach { (t, u) -> header(t, "$u") }
}
}
}
@ContextDsl
fun Application.register()
}
在這個(gè) Module 內(nèi),defaultRegister 是通過讀取 application.yml 內(nèi)的配置的參數(shù)來決定的,register 是用來讓用戶覆蓋,并實(shí)現(xiàn)額外的模塊注冊(cè)。
最后只需要實(shí)現(xiàn) Configuration 就可以了,這里實(shí)現(xiàn)讀取 yml 并且調(diào)用 defaultRegister 等方法:
/**
* spring.ktor 配置項(xiàng)
* @param host 服務(wù)器主機(jī)名
* @param port 綁定端口
* @param compress 是否啟用壓縮
* @param redirectHttps 是否自動(dòng)重定向到 https
* @param headers 默認(rèn)的請(qǐng)求頭
*/
@ConfigurationProperties(prefix = "spring.ktor")
open class KProperties(
open var host: String = "0.0.0.0",
open var port: Int = 8080,
open var compress: Boolean = false,
open var redirectHttps: Boolean = false,
open var headers: String = ""
)
用這個(gè)類來映射 yml 內(nèi)的配置,并且在取值后即可實(shí)現(xiàn)對(duì)模塊,路由等的初始化:
@Configuration
@EnableConfigurationProperties(KProperties::class)
open class KConfiguration {
@Resource
private lateinit var properties: KProperties
@Bean
@ConditionalOnMissingBean
open fun engineFactory() = Netty
@Bean
@ConditionalOnMissingBean
open fun applicationEngine(
engineFactory: ApplicationEngineFactory<ApplicationEngine, out ApplicationEngine.Configuration>,
context: ApplicationContext
): ApplicationEngine {
return embeddedServer(engineFactory, host = properties.host, port = properties.port) {
val modules = context.getBeansOfType(KModule::class.java).values
val routes = context.getBeansOfType(KRouter::class.java).values
modules.forEach { it.apply {
defaultRegister(
useCompress = properties.compress,
redirectHttps = properties.redirectHttps,
headers = properties.headers)
register()
} }
routing { routes.forEach { it.apply { route() } } }
}.start()
}
@Bean
@ConditionalOnMissingBean
open fun application(
applicationEngine: ApplicationEngine,
context: ApplicationContext
): Application = applicationEngine.environment.application
}
好了,一個(gè)簡(jiǎn)單的 starter 就完成了,最后加入一些配置就可以完成:
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.isyscore.ktor.starter.configuration.KConfiguration
然后加入對(duì)配置項(xiàng)的描述:
additional-spring-configuration-metadata.json
{
"properties": [
{
"name": "spring.ktor.port",
"type": "java.lang.Integer",
"description": "服務(wù)啟動(dòng)時(shí)使用的端口號(hào)."
},
{
"name": "spring.ktor.host",
"type": "java.lang.String",
"description": "服務(wù)的主機(jī)IP或域名."
},
{
"name": "spring.ktor.compress",
"type": "java.lang.Boolean",
"description": "是否啟用壓縮."
},
{
"name": "spring.ktor.redirectHttps",
"type": "java.lang.Boolean",
"description": "是否自動(dòng)重定向到 https."
},
{
"name": "spring.ktor.headers",
"type": "java.lang.String",
"description": "默認(rèn)的請(qǐng)求頭,以分號(hào)隔開."
}
]
}
最后我們只需要將這個(gè) starter 發(fā)布到私有的 nexus 就完成了:
$ gradle publish
使用 starter
新建一個(gè) SpringBoot 項(xiàng)目,并引入 starter:
implementation "com.rarnu:spring-boot-starter-ktor:0.0.1"
此時(shí)可以先在 yml 內(nèi)加入配置項(xiàng):
spring: ktor: port: 9000 compress: true headers: X-Engine=Ktor
然后來實(shí)現(xiàn) Configuration,Controller 和 Module:
TestConfiguration.kt
class TestConfiguration {
@Bean
fun engineFactory() = TestEngine
}
TestModule.kt
@Component
class TestModule : KModule {
override fun Application.register() {
// TODO: install custom plugins
}
}
TestController.kt
@Controller
class TestController : KRouter {
override fun Routing.route() {
request("/") {
call.respond(mapOf("code" to "001", "msg" to "操作成功。"))
}
get("/hello") {
call.respondText { "OK" }
}
}
}
完成后我們只需要寫一個(gè) Application,并且啟動(dòng)服務(wù)即可:
SpringKtorApplication.kt
@SpringBootApplication
open class SpringKtorApplication
fun main(args: Array<String>) {
runApplication<SpringKtorApplication>(*args)
}
現(xiàn)在就可以編譯項(xiàng)目并且運(yùn)行程序了:
$ gradle clean build $ java -jar test-ktor.jar
總結(jié)
現(xiàn)在即可使用 Ktor 的寫法來編寫 SpringBoot 的路由了
可以使用 Ktor 協(xié)程
可以使用各種方便的 Ktor 插件
用上 Ktor 后,代碼不麻煩了,心情也好了,效率更高了 :)
到此這篇關(guān)于spring boot與ktor整合的文章就介紹到這了,更多相關(guān)spring boot與ktor整合內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mac配置 maven以及環(huán)境變量設(shè)置方式
這篇文章主要介紹了Mac配置 maven以及環(huán)境變量設(shè)置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
JavaWeb監(jiān)聽器Listener實(shí)例解析
這篇文章主要為大家詳細(xì)介紹了JavaWeb監(jiān)聽器Listener實(shí)例,針對(duì)監(jiān)聽器進(jìn)行進(jìn)行細(xì)致分析,感興趣的小伙伴們可以參考一下2016-08-08
SWT(JFace)體驗(yàn)之FormLayout布局
SWT(JFace)體驗(yàn)之FormLayout布局示例代碼。2009-06-06
mybatis 獲取無數(shù)據(jù)的字段不顯示的問題
這篇文章主要介紹了mybatis 獲取無數(shù)據(jù)的字段不顯示的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
Java 實(shí)戰(zhàn)項(xiàng)目錘煉之網(wǎng)上商城系統(tǒng)的實(shí)現(xiàn)流程
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java+jsp+servlet+mysql+ajax實(shí)現(xiàn)一個(gè)網(wǎng)上商城系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11
SpringBoot啟動(dòng)security后如何關(guān)閉彈出的/login頁(yè)面
這篇文章主要介紹了SpringBoot啟動(dòng)security后如何關(guān)閉彈出的login頁(yè)面問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
java微信小程序步數(shù)encryptedData和開放數(shù)據(jù)解密的實(shí)現(xiàn)
這篇文章主要介紹了java微信小程序步數(shù)encryptedData和開放數(shù)據(jù)解密的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
IDEA里找不到Maven的有效解決辦法(小白超詳細(xì))
這篇文章主要給大家介紹了關(guān)于IDEA里找不到Maven的有效解決辦法,文中通過圖文將解決的辦法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07

