本篇文章給大家分享的是有關(guān)如何配置Spring Cloud的UnderTow并作為容器使用,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。
創(chuàng)新互聯(lián)建站是一家專(zhuān)業(yè)提供睢陽(yáng)企業(yè)網(wǎng)站建設(shè),專(zhuān)注與做網(wǎng)站、成都網(wǎng)站制作、HTML5建站、小程序制作等業(yè)務(wù)。10年已為睢陽(yáng)眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專(zhuān)業(yè)的建站公司優(yōu)惠進(jìn)行中。
在我們的項(xiàng)目中,我們沒(méi)有采用默認(rèn)的 Tomcat 容器,而是使用了 UnderTow 作為我們的容器。其實(shí)性能上的差異并沒(méi)有那么明顯,但是使用 UnderTow 我們可以利用直接內(nèi)存作為網(wǎng)絡(luò)傳輸?shù)?buffer,減少業(yè)務(wù)的 GC,優(yōu)化業(yè)務(wù)的表現(xiàn)。
**Undertow 的官網(wǎng)**:https://undertow.io/
但是,Undertow 有一些**令人擔(dān)憂**的地方:
NIO 框架采用的是 [XNIO](http://xnio.jboss.org/),在官網(wǎng) 3.0 roadmap 聲明中提到了將會(huì)在 3.0 版本開(kāi)始,從 XNIO 遷移到 netty, 參考:[Undertow 3.0 Announcement](https://undertow.io/blog/2019/04/15/Undertow-3.html)。但是,目前已經(jīng)過(guò)了快兩年了,**3.0 還是沒(méi)有發(fā)布,并且 github 上 3.0 的分支已經(jīng)一年多沒(méi)有更新了**。目前,還是在用 2.x 版本的 Undertow。不知道是 3.0 目前沒(méi)必要開(kāi)發(fā),還是胎死腹中了呢?目前國(guó)內(nèi)的環(huán)境對(duì)于 netty 使用更加廣泛并且大部分人對(duì)于 netty 更加熟悉一些, XNIO 應(yīng)用并不是很多。不過(guò),XNIO 的設(shè)計(jì)與 netty 大同小異。2. **官方文檔的更新比較慢,可能會(huì)慢 1~2 個(gè)小版本**,導(dǎo)致 Spring Boot 粘合 Undertow 的時(shí)候,配置顯得不會(huì)那么優(yōu)雅。**參考官方文檔的同時(shí),最好還是看一下源碼,至少看一下配置類(lèi),才能搞懂究竟是怎么設(shè)置的**。
**官方文檔的更新比較慢,可能會(huì)慢 1~2 個(gè)小版本**,導(dǎo)致 Spring Boot 粘合 Undertow 的時(shí)候,配置顯得不會(huì)那么優(yōu)雅。**參考官方文檔的同時(shí),最好還是看一下源碼,至少看一下配置類(lèi),才能搞懂究竟是怎么設(shè)置的**。
仔細(xì)看 Undertow 的源碼,會(huì)發(fā)現(xiàn)有很多防御性編程的設(shè)計(jì)或者功能性設(shè)計(jì) Undertow 的作者想到了,但是就是沒(méi)實(shí)現(xiàn),**有很多沒(méi)有實(shí)現(xiàn)的半成品代碼**。這也令人擔(dān)心 Underow 是否開(kāi)發(fā)動(dòng)力不足,哪一天會(huì)突然死掉?
**使用 Undertow 要注意的問(wèn)題**:
1. 需要開(kāi)啟 NIO DirectBuffer 的特性,理解并配置好相關(guān)的參數(shù)。
2. access.log 中要包括必要的一些時(shí)間,調(diào)用鏈等信息,并且默認(rèn)配置下,有些只配置 access.log 參數(shù)還是顯示不出來(lái)我們想看的信息,官網(wǎng)對(duì)于 access.log 中的參數(shù)的一些細(xì)節(jié)并沒(méi)有詳細(xì)說(shuō)明。
# 使用 Undertow 作為我們的 Web 服務(wù)容器
對(duì)于 Servlet 容器,依賴(lài)如下:
``` <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> ```
對(duì)于 Weflux 容器,依賴(lài)如下:
``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> ```
# Undertow 基本結(jié)構(gòu)
Undertow 目前(2.x) 還是基于 Java XNIO,Java XNIO 是一個(gè)對(duì)于 JDK NIO 類(lèi)的擴(kuò)展,和 netty 的基本功能是一樣的,但是 netty 更像是對(duì)于 Java NIO 的封裝,Java XNIO 更像是擴(kuò)展封裝。主要是 netty 中基本傳輸承載數(shù)據(jù)的并不是 Java NIO 中的 `ByteBuffer`,而是自己封裝的 `ByteBuf`,而 Java XNIO 各個(gè)接口設(shè)計(jì)還是基于 `ByteBuffer` 為傳輸處理單元。設(shè)計(jì)上也很相似,都是 Reactor 模型的設(shè)計(jì)。
Java XNIO 主要包括如下幾個(gè)概念:
- Java NIO `ByteBuffer`:`Buffer` 是一個(gè)具有狀態(tài)的數(shù)組,用來(lái)承載數(shù)據(jù),可以追蹤記錄已經(jīng)寫(xiě)入或者已經(jīng)讀取的內(nèi)容。主要屬性包括:capacity(Buffer 的容量),position(下一個(gè)要讀取或者寫(xiě)入的位置下標(biāo)),limit(當(dāng)前可以寫(xiě)入或者讀取的極限位置)。**程序必須通過(guò)將數(shù)據(jù)放入 Buffer,才能從 Channel 讀取或者寫(xiě)入數(shù)據(jù)**。`ByteBuffer`是更加特殊的 Buffer,它可以以直接內(nèi)存分配,這樣 JVM 可以直接利用這個(gè) Bytebuffer 進(jìn)行 IO 操作,省了一步復(fù)制(具體可以參考我的一篇文章:[Java 堆外內(nèi)存、零拷貝、直接內(nèi)存以及針對(duì)于NIO中的FileChannel的思考](https://zhuanlan.zhihu.com/p/161939673))。也可以通過(guò)文件映射內(nèi)存直接分配,即 Java MMAP(具體可以參考我的一篇文章:[JDK核心JAVA源碼解析(5) - JAVA File MMAP原理解析](https://zhuanlan.zhihu.com/p/258934554))。所以,一般的 IO 操作都是通過(guò) ByteBuffer 進(jìn)行的。
- Java NIO `Channel`:Channel 是 Java 中對(duì)于打開(kāi)和某一外部實(shí)體(例如硬件設(shè)備,文件,網(wǎng)絡(luò)連接 socket 或者可以執(zhí)行 IO 操作的某些組件)連接的抽象。Channel 主要是 IO 事件源,所有寫(xiě)入或者讀取的數(shù)據(jù)都必須經(jīng)過(guò) Channel。對(duì)于 NIO 的 Channel,會(huì)通過(guò) `Selector` 來(lái)通知事件的就緒(例如讀就緒和寫(xiě)就緒),之后通過(guò) Buffer 進(jìn)行讀取或者寫(xiě)入。
- XNIO `Worker`: Worker 是 Java XNIO 框架中的基本網(wǎng)絡(luò)處理單元,一個(gè) Worker 包含兩個(gè)不同的線程池類(lèi)型,分別是:
- **IO 線程池**,主要調(diào)用`Selector.start()`處理對(duì)應(yīng)事件的各種回調(diào),原則上不能處理任何阻塞的任務(wù),因?yàn)檫@樣會(huì)導(dǎo)致其他連接無(wú)法處理。IO 線程池包括兩種線程(在 XNIO 框架中,通過(guò)設(shè)置 WORKER_IO_THREADS 來(lái)設(shè)置這個(gè)線程池大小,默認(rèn)是一個(gè) CPU 一個(gè) IO 線程):
- **讀線程**:處理讀事件的回調(diào)
- **寫(xiě)線程**:處理寫(xiě)事件的回調(diào)
- **Worker 線程池**,處理阻塞的任務(wù),在 Web 服務(wù)器的設(shè)計(jì)中,一般將調(diào)用 servlet 任務(wù)放到這個(gè)線程池執(zhí)行(在 XNIO 框架中,通過(guò)設(shè)置 WORKER_TASK_CORE_THREADS 來(lái)設(shè)置這個(gè)線程池大?。?/p>
- XNIO `ChannelListener`:ChannelListener 是用來(lái)監(jiān)聽(tīng)處理 Channel 事件的抽象,包括:`channel readable`, `channel writable`, `channel opened`, `channel closed`, `channel bound`, `channel unbound`
Undertow 是基于 XNIO 的 Web 服務(wù)容器。在 XNIO 的基礎(chǔ)上,增加:
- Undertow `BufferPool`: 如果每次需要 ByteBuffer 的時(shí)候都去申請(qǐng),對(duì)于堆內(nèi)存的 ByteBuffer 需要走 JVM 內(nèi)存分配流程(TLAB -> 堆),對(duì)于直接內(nèi)存則需要走系統(tǒng)調(diào)用,這樣效率是很低下的。所以,一般都會(huì)引入內(nèi)存池。在這里就是 `BufferPool`。目前,UnderTow 中只有一種 `DefaultByteBufferPool`,其他的實(shí)現(xiàn)目前沒(méi)有用。這個(gè) DefaultByteBufferPool 相對(duì)于 netty 的 ByteBufArena 來(lái)說(shuō),非常簡(jiǎn)單,類(lèi)似于 JVM TLAB 的機(jī)制(可以參考我的另一系列:[全網(wǎng)最硬核 JVM TLAB 分析](https://juejin.cn/post/6925217498723778568)),但是簡(jiǎn)化了很多。**我們只需要配置 buffer size ,并開(kāi)啟使用直接內(nèi)存即可**。
- Undertow `Listener`: 默認(rèn)內(nèi)置有 3 種 Listener ,分別是 HTTP/1.1、AJP 和 HTTP/2 分別對(duì)應(yīng)的 Listener(HTTPS 通過(guò)對(duì)應(yīng)的 HTTP Listner 開(kāi)啟 SSL 實(shí)現(xiàn)),負(fù)責(zé)所有請(qǐng)求的解析,將請(qǐng)求解析后包裝成為 `HttpServerExchange` 并交給后續(xù)的 `Handler` 處理。
- Undertow `Handler`: 通過(guò) Handler 處理響應(yīng)的業(yè)務(wù),這樣組成一個(gè)完整的 Web 服務(wù)器。
# Undertow 的一些默認(rèn)配置
Undertow 的 Builder 設(shè)置了一些默認(rèn)的參數(shù),參考源碼:
[`Undertow`](https://github.com/undertow-io/undertow/blob/2.2.7.Final/core/src/main/java/io/undertow/Undertow.java)
``` private Builder() { ioThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2); workerThreads = ioThreads * 8; long maxMemory = Runtime.getRuntime().maxMemory(); //smaller than 64mb of ram we use 512b buffers if (maxMemory < 64 * 1024 * 1024) { //use 512b buffers directBuffers = false; bufferSize = 512; } else if (maxMemory < 128 * 1024 * 1024) { //use 1k buffers directBuffers = true; bufferSize = 1024; } else { //use 16k buffers for best performance //as 16k is generally the max amount of data that can be sent in a single write() call directBuffers = true; bufferSize = 1024 * 16 - 20; //the 20 is to allow some space for protocol headers, see UNDERTOW-1209 } } ```
- ioThreads 大小為可用 CPU 數(shù)量 * 2,即 Undertow 的 XNIO 的讀線程個(gè)數(shù)為可用 CPU 數(shù)量,寫(xiě)線程個(gè)數(shù)也為可用 CPU 數(shù)量。
- workerThreads 大小為 ioThreads 數(shù)量 * 8.
- 如果內(nèi)存大小小于 64 MB,則不使用直接內(nèi)存,bufferSize 為 512 字節(jié)
- 如果內(nèi)存大小大于 64 MB 小于 128 MB,則使用直接內(nèi)存,bufferSize 為 1024 字節(jié)
- 如果內(nèi)存大小大于 128 MB,則使用直接內(nèi)存,bufferSize 為 16 KB 減去 20 字節(jié),這 20 字節(jié)用于協(xié)議頭。
# Undertow Buffer Pool 配置
[`DefaultByteBufferPool`](https://github.com/undertow-io/undertow/blob/2.2.7.Final/core/src/main/java/io/undertow/server/DefaultByteBufferPool.java) 構(gòu)造器:
``` public DefaultByteBufferPool(boolean direct, int bufferSize, int maximumPoolSize, int threadLocalCacheSize, int leakDecetionPercent) { this.direct = direct; this.bufferSize = bufferSize; this.maximumPoolSize = maximumPoolSize; this.threadLocalCacheSize = threadLocalCacheSize; this.leakDectionPercent = leakDecetionPercent; if(direct) { arrayBackedPool = new DefaultByteBufferPool(false, bufferSize, maximumPoolSize, 0, leakDecetionPercent); } else { arrayBackedPool = this; } } ```
其中:
- direct:是否使用直接內(nèi)存,我們需要設(shè)置為 true,來(lái)使用直接內(nèi)存。
- bufferSize:每次申請(qǐng)的 buffer 大小,我們主要要考慮這個(gè)大小
- maximumPoolSize:buffer 池最大大小,一般不用修改
- threadLocalCacheSize:線程本地 buffer 池大小,一般不用修改
- leakDecetionPercent:內(nèi)存泄漏檢查百分比,目前沒(méi)啥卵用
對(duì)于 bufferSize,最好和你系統(tǒng)的 TCP Socket Buffer 配置一樣。在我們的容器中,我們將微服務(wù)實(shí)例的容器內(nèi)的 TCP Socket Buffer 的讀寫(xiě) buffer 大小成一模一樣的配置(因?yàn)槲⒎?wù)之間調(diào)用,發(fā)送的請(qǐng)求也是另一個(gè)微服務(wù)接受,所以調(diào)整所有微服務(wù)容器的讀寫(xiě) buffer 大小一致,來(lái)優(yōu)化性能,默認(rèn)是根據(jù)系統(tǒng)內(nèi)存來(lái)自動(dòng)計(jì)算出來(lái)的)。
查看 Linux 系統(tǒng) TCP Socket Buffer 的大小:
- `/proc/sys/net/ipv4/tcp_rmem` (對(duì)于讀取)
- `/proc/sys/net/ipv4/tcp_wmem` (對(duì)于寫(xiě)入)
在我們的容器中,分別是:
``` bash-4.2# cat /proc/sys/net/ipv4/tcp_rmem 4096 16384 4194304 bash-4.2# cat /proc/sys/net/ipv4/tcp_wmem 4096 16384 4194304 ```
從左到右三個(gè)值分別為:每個(gè) TCP Socket 的讀 Buffer 與寫(xiě) Buffer 的大小的 最小值,默認(rèn)值和最大值,單位是字節(jié)。
我們?cè)O(shè)置我們 Undertow 的 buffer size 為 TCP Socket Buffer 的默認(rèn)值,**即 16 KB**。Undertow 的 Builder 里面,如果內(nèi)存大于 128 MB,buffer size 為 16 KB 減去 20 字節(jié)(為協(xié)議頭預(yù)留)。所以,**我們使用默認(rèn)的即可**。
`application.yml` 配置:
``` server.undertow: # 是否分配的直接內(nèi)存(NIO直接分配的堆外內(nèi)存),這里開(kāi)啟,所以java啟動(dòng)參數(shù)需要配置下直接內(nèi)存大小,減少不必要的GC # 在內(nèi)存大于 128 MB 時(shí),默認(rèn)就是使用直接內(nèi)存的 directBuffers: true # 以下的配置會(huì)影響buffer,這些buffer會(huì)用于服務(wù)器連接的IO操作 # 如果每次需要 ByteBuffer 的時(shí)候都去申請(qǐng),對(duì)于堆內(nèi)存的 ByteBuffer 需要走 JVM 內(nèi)存分配流程(TLAB -> 堆),對(duì)于直接內(nèi)存則需要走系統(tǒng)調(diào)用,這樣效率是很低下的。 # 所以,一般都會(huì)引入內(nèi)存池。在這里就是 `BufferPool`。 # 目前,UnderTow 中只有一種 `DefaultByteBufferPool`,其他的實(shí)現(xiàn)目前沒(méi)有用。 # 這個(gè) DefaultByteBufferPool 相對(duì)于 netty 的 ByteBufArena 來(lái)說(shuō),非常簡(jiǎn)單,類(lèi)似于 JVM TLAB 的機(jī)制 # 對(duì)于 bufferSize,最好和你系統(tǒng)的 TCP Socket Buffer 配置一樣 # `/proc/sys/net/ipv4/tcp_rmem` (對(duì)于讀取) # `/proc/sys/net/ipv4/tcp_wmem` (對(duì)于寫(xiě)入) # 在內(nèi)存大于 128 MB 時(shí),bufferSize 為 16 KB 減去 20 字節(jié),這 20 字節(jié)用于協(xié)議頭 buffer-size: 16384 - 20 ```
# Undertow Worker 配置
Worker 配置其實(shí)就是 XNIO 的核心配置,主要需要配置的即 io 線程池以及 worker 線程池大小。
默認(rèn)情況下,io 線程大小為可用 CPU 數(shù)量 * 2,即讀線程個(gè)數(shù)為可用 CPU 數(shù)量,寫(xiě)線程個(gè)數(shù)也為可用 CPU 數(shù)量。worker 線程池大小為 io 線程大小 * 8.
微服務(wù)應(yīng)用由于涉及的阻塞操作比較多,所以可以將 worker 線程池大小調(diào)大一些。我們的應(yīng)用設(shè)置為 io 線程大小 * 32.
`application.yml` 配置:
``` server.undertow.threads: # 設(shè)置IO線程數(shù), 它主要執(zhí)行非阻塞的任務(wù),它們會(huì)負(fù)責(zé)多個(gè)連接, 默認(rèn)設(shè)置每個(gè)CPU核心一個(gè)讀線程和一個(gè)寫(xiě)線程 io: 16 # 阻塞任務(wù)線程池, 當(dāng)執(zhí)行類(lèi)似servlet請(qǐng)求阻塞IO操作, undertow會(huì)從這個(gè)線程池中取得線程 # 它的值設(shè)置取決于系統(tǒng)線程執(zhí)行任務(wù)的阻塞系數(shù),默認(rèn)值是IO線程數(shù)*8 worker: 128 ```
# Spring Boot 中的 Undertow 配置
Spring Boot 中對(duì)于 Undertow 相關(guān)配置的抽象是 [`ServerProperties`](https://github.com/spring-projects/spring-boot/blob/2.4.x/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java) 這個(gè)類(lèi)。目前 Undertow 涉及的所有配置以及說(shuō)明如下(不包括 accesslog 相關(guān)的,accesslog 會(huì)在下一節(jié)詳細(xì)分析):
``` server: undertow: # 以下的配置會(huì)影響buffer,這些buffer會(huì)用于服務(wù)器連接的IO操作 # 如果每次需要 ByteBuffer 的時(shí)候都去申請(qǐng),對(duì)于堆內(nèi)存的 ByteBuffer 需要走 JVM 內(nèi)存分配流程(TLAB -> 堆),對(duì)于直接內(nèi)存則需要走系統(tǒng)調(diào)用,這樣效率是很低下的。 # 所以,一般都會(huì)引入內(nèi)存池。在這里就是 `BufferPool`。 # 目前,UnderTow 中只有一種 `DefaultByteBufferPool`,其他的實(shí)現(xiàn)目前沒(méi)有用。 # 這個(gè) DefaultByteBufferPool 相對(duì)于 netty 的 ByteBufArena 來(lái)說(shuō),非常簡(jiǎn)單,類(lèi)似于 JVM TLAB 的機(jī)制 # 對(duì)于 bufferSize,最好和你系統(tǒng)的 TCP Socket Buffer 配置一樣 # `/proc/sys/net/ipv4/tcp_rmem` (對(duì)于讀取) # `/proc/sys/net/ipv4/tcp_wmem` (對(duì)于寫(xiě)入) # 在內(nèi)存大于 128 MB 時(shí),bufferSize 為 16 KB 減去 20 字節(jié),這 20 字節(jié)用于協(xié)議頭 buffer-size: 16364 # 是否分配的直接內(nèi)存(NIO直接分配的堆外內(nèi)存),這里開(kāi)啟,所以java啟動(dòng)參數(shù)需要配置下直接內(nèi)存大小,減少不必要的GC # 在內(nèi)存大于 128 MB 時(shí),默認(rèn)就是使用直接內(nèi)存的 directBuffers: true threads: # 設(shè)置IO線程數(shù), 它主要執(zhí)行非阻塞的任務(wù),它們會(huì)負(fù)責(zé)多個(gè)連接, 默認(rèn)設(shè)置每個(gè)CPU核心一個(gè)讀線程和一個(gè)寫(xiě)線程 io: 4 # 阻塞任務(wù)線程池, 當(dāng)執(zhí)行類(lèi)似servlet請(qǐng)求阻塞IO操作, undertow會(huì)從這個(gè)線程池中取得線程 # 它的值設(shè)置取決于系統(tǒng)線程執(zhí)行任務(wù)的阻塞系數(shù),默認(rèn)值是IO線程數(shù)*8 worker: 128 # http post body 大小,默認(rèn)為 -1B ,即不限制 max-http-post-size: -1B # 是否在啟動(dòng)時(shí)創(chuàng)建 filter,默認(rèn)為 true,不用修改 eager-filter-init: true # 限制路徑參數(shù)數(shù)量,默認(rèn)為 1000 max-parameters: 1000 # 限制 http header 數(shù)量,默認(rèn)為 200 max-headers: 200 # 限制 http header 中 cookies 的鍵值對(duì)數(shù)量,默認(rèn)為 200 max-cookies: 200 # 是否允許 / 與 %2F 轉(zhuǎn)義。/ 是 URL 保留字,除非你的應(yīng)用明確需要,否則不要開(kāi)啟這個(gè)轉(zhuǎn)義,默認(rèn)為 false allow-encoded-slash: false # 是否允許 URL 解碼,默認(rèn)為 true,除了 %2F 其他的都會(huì)處理 decode-url: true # url 字符編碼集,默認(rèn)是 utf-8 url-charset: utf-8 # 響應(yīng)的 http header 是否會(huì)加上 'Connection: keep-alive',默認(rèn)為 true always-set-keep-alive: true # 請(qǐng)求超時(shí),默認(rèn)是不超時(shí),我們的微服務(wù)因?yàn)榭赡苡虚L(zhǎng)時(shí)間的定時(shí)任務(wù),所以不做服務(wù)端超時(shí),都用客戶(hù)端超時(shí),所以我們保持這個(gè)默認(rèn)配置 no-request-timeout: -1 # 是否在跳轉(zhuǎn)的時(shí)候保持 path,默認(rèn)是關(guān)閉的,一般不用配置 preserve-path-on-forward: false options: # spring boot 沒(méi)有抽象的 xnio 相關(guān)配置在這里配置,對(duì)應(yīng) org.xnio.Options 類(lèi) socket: SSL_ENABLED: false # spring boot 沒(méi)有抽象的 undertow 相關(guān)配置在這里配置,對(duì)應(yīng) io.undertow.UndertowOptions 類(lèi) server: ALLOW_UNKNOWN_PROTOCOLS: false ```
Spring Boot 并沒(méi)有將所有的 Undertow 與 XNIO 配置進(jìn)行抽象,如果你想自定義一些相關(guān)配置,可以通過(guò)上面配置最后的 `server.undertow.options` 進(jìn)行配置。`server.undertow.options.socket` 對(duì)應(yīng) XNIO 的相關(guān)配置,配置類(lèi)是 `org.xnio.Options`;`server.undertow.options.server` 對(duì)應(yīng) Undertow 的相關(guān)配置,配置類(lèi)是 `io.undertow.UndertowOptions`。http://www.2798888.com/
以上就是如何配置Spring Cloud的UnderTow并作為容器使用,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
文章題目:如何配置SpringCloud的UnderTow并作為容器使用
路徑分享:http://chinadenli.net/article28/ihjpcp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、建站公司、企業(yè)建站、虛擬主機(jī)、網(wǎng)站導(dǎo)航、網(wǎng)站營(yíng)銷(xiāo)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)