[netty5: MessageAggregator HttpObjectAggregator]-源碼解析

在閱讀這篇文章前,推薦先閱讀

  1. [netty5: ByteToMessageCodec & MessageToByteEncoder & ByteToMessageDecoder]-源碼分析
  2. [netty5: HttpObject]-源碼解析

100-continue

100-continue 是 HTTP/1.1 協議中的一種機制,用于客戶端在發送大體積請求體(如文件上傳)前,先向服務器發送一個帶有 Expect: 100-continue 頭的請求,詢問服務器是否準備好接收請求體;服務器如果準備好了,會返回 100 Continue 響應,客戶端才開始發送實際數據,從而避免不必要的大數據傳輸。

MessageAggregator

MessageAggregator<I, S, C, A> 是一個高度可復用的通用聚合器框架,適用于各種流式協議的“分段消息聚合”場景:

功能說明
啟動聚合tryStartMessage() 檢測到起始消息,初始化聚合
聚合中tryContentMessage() 檢測到內容消息,append 內容
完成聚合isLastContentMessage() 判斷是否是最后一塊,調用 finishAggregation
超長控制maxContentLength + lengthForContent 控制體積
特殊控制支持 100-continue、異常處理、復用 context listener
public abstract class MessageAggregator<I, S, C extends AutoCloseable, A extends AutoCloseable> extends MessageToMessageDecoder<I> {// 當前正在聚合的完整消息(例如 FullHttpRequest 或 FullHttpResponse)private A currentMessage;// 聚合內容允許的最大字節數,超過則觸發 handleOversizedMessageprivate final int maxContentLength;// 標識當前是否正在處理超長消息,避免重復處理。private boolean handlingOversizedMessage;private ChannelHandlerContext ctx;// 用于監聽 100-Continue 響應寫入完成后的回調private FutureContextListener<ChannelHandlerContext, Void> continueResponseWriteListener;// 標識是否正在聚合過程中private boolean aggregating;// 是否在通道關閉時處理未完成的聚合private boolean handleIncompleteAggregateDuringClose = true;protected MessageAggregator(int maxContentLength) {this.maxContentLength = maxContentLength;}@Overridepublic boolean acceptInboundMessage(Object msg) throws Exception {if (!super.acceptInboundMessage(msg)) {return false;}if (isAggregated(msg)) {return false;}if (tryStartMessage(msg) != null) {return true;}return aggregating && tryContentMessage(msg) != null;}@Overrideprotected void decode(final ChannelHandlerContext ctx, I msg) throws Exception {// 1. 判斷是否為新消息起始(startMsg)// 判斷當前收到的 msg 是否為 HttpMessage,如果是,則開始處理聚合。final S startMsg = tryStartMessage(msg);if (startMsg != null) {aggregating = true;handlingOversizedMessage = false;// 如果已存在未完成的 currentMessage,說明消息異常,拋出 MessageAggregationExceptionif (currentMessage != null) {currentMessage.close();currentMessage = null;throw new MessageAggregationException();}// 2. 處理 100-continue 相關響應(continueResponse)// newContinueResponse 的核心邏輯:// - 如果請求頭中包含 Expect: 100-continue,并且請求體大小沒有超過 maxContentLength,則返回一個 100 Continue 響應;// - 如果請求體過大(Content-Length > maxContentLength),則返回一個 413 Request Entity Too Large 錯誤響應;// - 如果不符合任何條件,返回 null,表示不需要繼續響應。Object continueResponse = newContinueResponse(startMsg, maxContentLength, ctx.pipeline());if (continueResponse != null) {// 構造監聽器FutureContextListener<ChannelHandlerContext, Void> listener = continueResponseWriteListener;if (listener == null) {continueResponseWriteListener = listener = (context, future) -> {if (future.isFailed()) {context.fireChannelExceptionCaught(future.cause());}};}// 判斷在收到 100-continue 響應后是否關閉連接,條件是配置了關閉標志且響應表示應忽略后續內容。boolean closeAfterWrite = closeAfterContinueResponse(continueResponse);// 	// 判斷響應是否為客戶端錯誤(4xx),如果是,則說明應忽略后續內容。handlingOversizedMessage = ignoreContentAfterContinueResponse(continueResponse);// 寫出響應并監聽結果Future<Void> future = ctx.writeAndFlush(continueResponse).addListener(ctx, listener);if (closeAfterWrite) {handleIncompleteAggregateDuringClose = false;future.addListener(ctx, ChannelFutureListeners.CLOSE);return;}// 判斷是否忽略后續內容if (handlingOversizedMessage) {return;}} else if (isContentLengthInvalid(startMsg, maxContentLength)) {// 3. 檢查請求長度是否合法invokeHandleOversizedMessage(ctx, startMsg);return;}// 4. 處理起始消息中已有的解碼失敗情況if (startMsg instanceof DecoderResultProvider &&!((DecoderResultProvider) startMsg).decoderResult().isSuccess()) {final A aggregated = beginAggregation(ctx.bufferAllocator(), startMsg);finishAggregation(ctx.bufferAllocator(), aggregated);ctx.fireChannelRead(aggregated);return;}// 5. 初始化新消息聚合對象// 創建一個聚合消息實例(包含起始行和一個空的內容緩沖區),等待后續內容片段加入。currentMessage = beginAggregation(ctx.bufferAllocator(), startMsg);return;}// 6. 處理內容消息(contentMsg)// 先判斷 msg 是否是消息體片段,如果不是則拋異常。final C contentMsg = tryContentMessage(msg);if (contentMsg != null) {// 如果還沒有初始化的聚合消息(即沒有起始消息),忽略該內容。if (currentMessage == null) {return;}// 檢查聚合后長度是否超限,超限則調用超長消息處理。if (lengthForAggregation(currentMessage) > maxContentLength - lengthForContent(contentMsg)) {invokeHandleOversizedMessage(ctx, currentMessage);return;}// 調用 aggregate 將當前內容片段追加到聚合消息。aggregate(ctx.bufferAllocator(), currentMessage, contentMsg);final boolean last;// 檢查是否為消息最后一片(last)if (contentMsg instanceof DecoderResultProvider) {DecoderResult decoderResult = ((DecoderResultProvider) contentMsg).decoderResult();if (!decoderResult.isSuccess()) {if (currentMessage instanceof DecoderResultProvider) {((DecoderResultProvider) currentMessage).setDecoderResult(DecoderResult.failure(decoderResult.cause()));}last = true;} else {last = isLastContentMessage(contentMsg);}} else {last = isLastContentMessage(contentMsg);}// 如果是,完成聚合,清理狀態,向下游傳遞完整消息。if (last) {finishAggregation0(ctx.bufferAllocator(), currentMessage);// All doneA message = currentMessage;currentMessage = null;ctx.fireChannelRead(message);}} else {throw new MessageAggregationException();}}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {if (currentMessage != null && !ctx.channel().getOption(ChannelOption.AUTO_READ)) {ctx.read();}ctx.fireChannelReadComplete();}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {if (aggregating && handleIncompleteAggregateDuringClose) {ctx.fireChannelExceptionCaught(new PrematureChannelClosureException("Channel closed while still aggregating message"));}try {super.channelInactive(ctx);} finally {releaseCurrentMessage();}}@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {this.ctx = ctx;}@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {try {super.handlerRemoved(ctx);} finally {releaseCurrentMessage();}}protected final void releaseCurrentMessage() throws Exception {if (currentMessage != null) {currentMessage.close();currentMessage = null;}handlingOversizedMessage = false;aggregating = false;}// 省略抽象方法,具體看 HttpObjectAggregator
}

HttpObjectAggregator

HttpObjectAggregator 是構建高層 HTTP 服務的基礎設施組件,它將分塊的 HTTP 請求或響應組裝為完整對象,從而簡化上層應用邏輯。其設計清晰、可擴展性強,并充分考慮了 Expect: 100-continue 與 Content-Length 異常等 HTTP 協議邊界情況,是非常值得借鑒的聚合處理器實現。

public class HttpObjectAggregator<C extends HttpContent<C>>extends MessageAggregator<HttpObject, HttpMessage, HttpContent<C>, FullHttpMessage<?>> {private static final Logger logger = LoggerFactory.getLogger(HttpObjectAggregator.class);// 當檢測到客戶端發送了 100-continue 期望但請求內容過大時,是否關閉連接;// 為 true 則直接關閉連接,防止浪費資源,// 為 false 則保持連接打開并繼續讀取和丟棄數據直到下一請求。private final boolean closeOnExpectationFailed;public HttpObjectAggregator(int maxContentLength) {this(maxContentLength, false);}public HttpObjectAggregator(int maxContentLength, boolean closeOnExpectationFailed) {super(maxContentLength);this.closeOnExpectationFailed = closeOnExpectationFailed;}@Overrideprotected HttpMessage tryStartMessage(Object msg) {return msg instanceof HttpMessage ? (HttpMessage) msg : null;}@SuppressWarnings("unchecked")@Overrideprotected HttpContent<C> tryContentMessage(Object msg) {return msg instanceof HttpContent ? (HttpContent<C>) msg : null;}@Overrideprotected boolean isAggregated(Object msg) throws Exception {return msg instanceof FullHttpMessage;}@Overrideprotected int lengthForContent(HttpContent<C> msg) {return msg.payload().readableBytes();}@Overrideprotected int lengthForAggregation(FullHttpMessage<?> msg) {return msg.payload().readableBytes();}@Overrideprotected boolean isLastContentMessage(HttpContent<C> msg) throws Exception {return msg instanceof LastHttpContent;}@Overrideprotected boolean isContentLengthInvalid(HttpMessage start, int maxContentLength) {try {return getContentLength(start, -1L) > maxContentLength;} catch (final NumberFormatException e) {return false;}}// 根據請求的 Expectation 頭判斷是否返回 100 Continue 或錯誤響應(如 417 或 413),并在不支持或內容過大時觸發相應事件private static FullHttpResponse continueResponse(HttpMessage start, int maxContentLength, ChannelPipeline pipeline) {// 根據請求的 Expectation 頭判斷是否支持期望,若不支持觸發失敗事件返回 417;if (HttpUtil.isUnsupportedExpectation(start)) {pipeline.fireChannelInboundEvent(HttpExpectationFailedEvent.INSTANCE);return newErrorResponse(EXPECTATION_FAILED, pipeline.channel().bufferAllocator(), true, false);}if (HttpUtil.is100ContinueExpected(start)) {// 若期望 100-continue 且內容長度未超限,返回 100 Continue 響應,if (getContentLength(start, -1L) <= maxContentLength) {return newErrorResponse(CONTINUE, pipeline.channel().bufferAllocator(), false, false);}// 否則觸發失敗事件并返回 413 請求體過大響應。pipeline.fireChannelInboundEvent(HttpExpectationFailedEvent.INSTANCE);return newErrorResponse(REQUEST_ENTITY_TOO_LARGE, pipeline.channel().bufferAllocator(), true, false);}return null;}// 根據請求創建一個 100-continue 響應,并在響應生成后移除請求中的 Expect 頭。@Overrideprotected Object newContinueResponse(HttpMessage start, int maxContentLength, ChannelPipeline pipeline) {FullHttpResponse response = continueResponse(start, maxContentLength, pipeline);if (response != null) {start.headers().remove(EXPECT);}return response;}// 判斷在收到 100-continue 響應后是否關閉連接,條件是配置了關閉標志且響應表示應忽略后續內容。@Overrideprotected boolean closeAfterContinueResponse(Object msg) {return closeOnExpectationFailed && ignoreContentAfterContinueResponse(msg);}// 判斷響應是否為客戶端錯誤(4xx),如果是,則說明應忽略后續內容。@Overrideprotected boolean ignoreContentAfterContinueResponse(Object msg) {if (msg instanceof HttpResponse) {final HttpResponse httpResponse = (HttpResponse) msg;return httpResponse.status().codeClass() == HttpStatusClass.CLIENT_ERROR;}return false;}// 開始對一個非完整的 HTTP 消息進行聚合,移除分塊傳輸編碼標記,并創建一個對應請求或響應類型的空聚合消息,準備接收后續內容。@Overrideprotected FullHttpMessage<?> beginAggregation(BufferAllocator allocator, HttpMessage start) throws Exception {assert !(start instanceof FullHttpMessage);// 移除 HTTP 消息頭中的 Transfer-Encoding: chunked,以便后續使用聚合后的 Content-LengthHttpUtil.setTransferEncodingChunked(start, false);final CompositeBuffer content = allocator.compose();FullHttpMessage<?> ret;// 根據消息類型創建對應的聚合消息并初始化其 payload 為一個可擴展的空 CompositeBuffer,用于后續追加內容塊。if (start instanceof HttpRequest) {ret = new AggregatedFullHttpRequest((HttpRequest) start, content, null);} else if (start instanceof HttpResponse) {ret = new AggregatedFullHttpResponse((HttpResponse) start, content, null);} else {throw new Error();}return ret;}// 將內容塊追加到聚合消息中,并在遇到最后一塊時設置尾部頭信息@Overrideprotected void aggregate(BufferAllocator allocator, FullHttpMessage<?> aggregated, HttpContent<C> content) throws Exception {final CompositeBuffer payload = (CompositeBuffer) aggregated.payload();payload.extendWith(content.payload().send());if (content instanceof LastHttpContent) {((AggregatedFullHttpMessage<?>) aggregated).setTrailingHeaders(((LastHttpContent<?>) content).trailingHeaders());}}// 完成聚合時,如果未設置 Content-Length,則自動設置為聚合內容的實際長度。@Overrideprotected void finishAggregation(BufferAllocator allocator, FullHttpMessage<?> aggregated) throws Exception {if (!HttpUtil.isContentLengthSet(aggregated)) {aggregated.headers().set(CONTENT_LENGTH, String.valueOf(aggregated.payload().readableBytes()));}}// 處理超大 HTTP 消息@Overrideprotected void handleOversizedMessage(final ChannelHandlerContext ctx, Object oversized) throws Exception {if (oversized instanceof HttpRequest) {HttpRequest request = (HttpRequest) oversized;// 條件1:如果是完整請求(FullHttpMessage)或者請求既不期待100-continue也不保持連接if (oversized instanceof FullHttpMessage || !HttpUtil.is100ContinueExpected(request) && !HttpUtil.isKeepAlive(request)) {// 發送帶關閉連接指示的413錯誤響應Future<Void> future = ctx.writeAndFlush(newErrorResponse(REQUEST_ENTITY_TOO_LARGE, ctx.bufferAllocator(), true, true));future.addListener(f -> {if (f.isFailed()) {// 日志打印發送失敗的原因logger.debug("Failed to send a 413 Request Entity Too Large.", f.cause());}// 響應發送后關閉連接ctx.close();});} else {// 條件2:請求期待100-continue或者保持連接時,發送不關閉連接的413響應ctx.writeAndFlush(newErrorResponse(REQUEST_ENTITY_TOO_LARGE, ctx.bufferAllocator(), true, false)).addListener(future -> {if (future.isFailed()) {// 發送失敗時日志記錄并關閉連接logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());ctx.close();}});}} else if (oversized instanceof HttpResponse) {// 如果是超大的響應,直接拋出異常,可能交由上層處理throw new ResponseTooLargeException("Response entity too large: " + oversized);} else {// 既不是請求也不是響應,視為非法狀態,拋異常throw new IllegalStateException();}}@Overridepublic void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {super.channelExceptionCaught(ctx, cause);if (cause instanceof ResponseTooLargeException) {ctx.close();}}// 該方法用于生成一個指定狀態碼的空響應,并根據參數決定是否關閉連接和設置內容長度private static FullHttpResponse newErrorResponse(HttpResponseStatus status, BufferAllocator allocator, boolean emptyContent, boolean closeConnection) {// 根據傳入的狀態碼 status,創建一個空內容的 FullHttpResponse,FullHttpResponse resp = new DefaultFullHttpResponse(HTTP_1_1, status, allocator.allocate(0));// 如果 emptyContent 為 true,則設置響應頭 Content-Length 為 0,if (emptyContent) {resp.headers().set(CONTENT_LENGTH, HttpHeaderValues.ZERO);}// 如果 closeConnection 為 true,則設置響應頭 Connection: close,表示連接關閉。if (closeConnection) {resp.headers().set(CONNECTION, HttpHeaderValues.CLOSE);}return resp;}
}

AggregatedFullHttpMessage

private abstract static class AggregatedFullHttpMessage<R extends FullHttpMessage<R>> implements FullHttpMessage<R> {protected final HttpMessage message;private final Buffer payload;private HttpHeaders trailingHeaders;AggregatedFullHttpMessage(HttpMessage message, Buffer payload, HttpHeaders trailingHeaders) {this.message = message;this.payload = payload;this.trailingHeaders = trailingHeaders;}@Overridepublic void close() {payload.close();}@Overridepublic boolean isAccessible() {return payload.isAccessible();}@Overridepublic Buffer payload() {return payload;}@Overridepublic HttpHeaders trailingHeaders() {HttpHeaders trailingHeaders = this.trailingHeaders;return requireNonNullElse(trailingHeaders, HttpHeaders.emptyHeaders());}void setTrailingHeaders(HttpHeaders trailingHeaders) {this.trailingHeaders = trailingHeaders;}@Overridepublic HttpVersion getProtocolVersion() {return message.protocolVersion();}@Overridepublic HttpVersion protocolVersion() {return message.protocolVersion();}@Overridepublic FullHttpMessage<R> setProtocolVersion(HttpVersion version) {message.setProtocolVersion(version);return this;}@Overridepublic HttpHeaders headers() {return message.headers();}@Overridepublic DecoderResult decoderResult() {return message.decoderResult();}@Overridepublic void setDecoderResult(DecoderResult result) {message.setDecoderResult(result);}
}

AggregatedFullHttpRequest

private static final class AggregatedFullHttpRequest extends AggregatedFullHttpMessage<FullHttpRequest> implements FullHttpRequest {AggregatedFullHttpRequest(HttpRequest request, Buffer content, HttpHeaders trailingHeaders) {super(request, content, trailingHeaders);}@Overridepublic Send<FullHttpRequest> send() {return payload().send().map(FullHttpRequest.class,p -> new AggregatedFullHttpRequest(this, p, trailingHeaders()));}@Overridepublic AggregatedFullHttpRequest copy() {return new AggregatedFullHttpRequest(this, payload().copy(), trailingHeaders().copy());}@Overridepublic FullHttpRequest touch(Object hint) {payload().touch(hint);return this;}@Overridepublic FullHttpRequest setMethod(HttpMethod method) {((HttpRequest) message).setMethod(method);return this;}@Overridepublic FullHttpRequest setUri(String uri) {((HttpRequest) message).setUri(uri);return this;}@Overridepublic HttpMethod method() {return ((HttpRequest) message).method();}@Overridepublic String uri() {return ((HttpRequest) message).uri();}@Overridepublic FullHttpRequest setProtocolVersion(HttpVersion version) {super.setProtocolVersion(version);return this;}@Overridepublic String toString() {return HttpMessageUtil.appendFullRequest(new StringBuilder(256), this).toString();}
}

AggregatedFullHttpResponse

private static final class AggregatedFullHttpResponse extends AggregatedFullHttpMessage<FullHttpResponse> implements FullHttpResponse {AggregatedFullHttpResponse(HttpResponse message, Buffer content, HttpHeaders trailingHeaders) {super(message, content, trailingHeaders);}@Overridepublic Send<FullHttpResponse> send() {return payload().send().map(FullHttpResponse.class,p -> new AggregatedFullHttpResponse(this, p, trailingHeaders()));}@Overridepublic AggregatedFullHttpResponse copy() {return new AggregatedFullHttpResponse(this, payload().copy(), trailingHeaders().copy());}@Overridepublic FullHttpResponse touch(Object hint) {payload().touch(hint);return this;}@Overridepublic FullHttpResponse setStatus(HttpResponseStatus status) {((HttpResponse) message).setStatus(status);return this;}@Overridepublic HttpResponseStatus status() {return ((HttpResponse) message).status();}@Overridepublic FullHttpResponse setProtocolVersion(HttpVersion version) {super.setProtocolVersion(version);return this;}@Overridepublic String toString() {return HttpMessageUtil.appendFullResponse(new StringBuilder(256), this).toString();}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/90314.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/90314.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/90314.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端學習1--行內元素 vs 塊級元素(基礎概念+案例實操)

一、內外邊距學習&#xff1a;&#xff08;1&#xff09;簡單理解&#xff1a;padding為內邊距。padding不會影響元素的位置&#xff0c;只會調整元素的內容&#xff08;文字&#xff09;與邊框之間的間距。margin為外邊距。margin會影響元素在流式布局中的位置&#xff0c;改變…

Express + mysql2 + jwt 實現簡單的登錄鑒權

目前項目中使用Express 實現簡單API功能&#xff0c;需要提供一套登錄鑒權方案。這邊是API側實現 相關路由的登錄鑒權。大體思路&#xff1a;就是&#xff0c;登錄接口中通過jwt加密 token返回前端&#xff0c;前端其他接口把加密好的放入請求頭Authorization中。中間件通過請求…

ReAct (Reason and Act) OR 強化學習(Reinforcement Learning, RL)

這個問題觸及了現代AI智能體&#xff08;Agent&#xff09;構建的兩種核心思想。 簡單來說&#xff0c;ReAct 是一種“調用專家”的模式&#xff0c;而強化學習 (RL) 是一種“從零試錯”的模式。 為了讓你更清晰地理解&#xff0c;我們從一個生動的比喻開始&#xff0c;然后進行…

iTwinjs 4.10-4.11 更新

撤銷更改 目前&#xff0c;撤銷一個有缺陷的變更集的唯一方法是從 iModel Hub 中移除它&#xff0c;這可能會導致許多副作用&#xff08;無法撤銷&#xff09;。一個更好的方法是在時間線中撤銷變更集&#xff0c;并將其作為新的變更集引入。盡管這種方法仍然具有侵入性&#…

【CSS-15】深入理解CSS transition-duration:掌握過渡動畫的時長控制

在現代網頁設計中&#xff0c;平滑的過渡效果是提升用戶體驗的關鍵因素之一。CSS transitions 為我們提供了一種簡單而強大的方式來實現元素在不同狀態之間的平滑過渡&#xff0c;而 transition-duration 屬性則是控制這些過渡效果時長的核心工具。本文將全面探討 transition-d…

mysql-筆記

1. 安裝mysql # 使用brew安裝 brew install mysql# 查看是否安裝成功 mysql -V 相關文檔&#xff1a; mac&#xff1a;macOS下MySQL 8.0 安裝與配置教程 - KenTalk - 博客園 Linux安裝&#xff1a;linux安裝mysql客戶端_linux mysql 客戶端-CSDN博客 2. 啟動mysql 每次使…

Spring Boot啟動優化7板斧(延遲初始化、組件掃描精準打擊、JVM參數調優):砍掉70%啟動時間的魔鬼實踐

Spring Boot啟動優化7板斧&#xff1a;砍掉70%啟動時間的魔鬼實踐1. 延遲初始化&#xff1a;按需加載的智慧2. 組件掃描精準打擊&#xff1a;告別無差別掃描3. JVM參數調優&#xff1a;啟動加速的隱藏開關4. 自動配置瘦身&#xff1a;砍掉Spring Boot的"贅肉"5. 類加…

從0開始學習計算機視覺--Day08--卷積神經網絡

之前我們提到&#xff0c;神經網絡是通過全連接層對輸入做降維處理&#xff0c;將輸入的向量通過矩陣和激活函數進行降維&#xff0c;在神經元上輸出激活值。而卷積神經網絡中&#xff0c;用卷積層代替了全連接層。 不同的是&#xff0c;這里的輸入不再需要降維&#xff0c;而…

解決阿里云ubuntu內存溢出導致vps死機無法訪問 - 永久性增加ubuntu的swap空間 - 阿里云Linux實例內存溢出(OOM)問題修復方案

效果圖報錯通過對實例當前截屏的分析發現&#xff0c;實例因 Linux實例內存空間不足&#xff0c;導致操作系統出現內存溢出&#xff08;OOM&#xff09; 無法正常啟動。請您根據 Code&#xff1a;1684829582&#xff0c;在文檔中查詢該問題對應的修復方案&#xff0c;并通過VNC…

Serverless JManus: 企業生產級通用智能體運行時

作者&#xff1a;叢霄、陸龜 概述&#xff1a;本文介紹如何使用 JManus 框架構建通用智能體應用&#xff0c;部署并運行在 Serverless 運行時&#xff0c;構建企業級高可用智能體應用的實踐經驗。基于阿里云 Serverless 應用引擎SAE 運行穩定高可用的智能體應用&#xff0c; 基…

MySQL的數據目錄

導讀&#xff1a;根據前面的所學知識&#xff0c;我們知道了InnoDB存儲引擎存儲數據的數據結構、存儲過程&#xff0c;而被組織好的數據則被存儲在操作系統的磁盤上&#xff0c;當我們在對表數據進行增刪改查時&#xff0c;其實就是InnoDB存儲引擎與磁盤的交互。此外&#xff0…

Web前端開發: :has功能性偽類選擇器

:has功能性偽類選擇器::has() 是 CSS 中的一個功能性偽類選擇器&#xff0c;它允許開發者根據元素的后代元素、兄弟元素或后續元素的存在或狀態來選擇目標元素。它本質上是一個“父選擇器”或“關系選擇器”&#xff0c;解決了 CSS 長期以來無法根據子元素反向選擇父元素的痛點…

深度學習8(梯度下降算法改進2)

目錄 RMSProp 算法 Adam算法 學習率衰減 RMSProp 算法 RMSProp(Root Mean Square Prop)算法是在對梯度進行指數加權平均的基礎上&#xff0c;引入平方和平方根。 其中e是一個非常小的數&#xff0c;防止分母太小導致不穩定,當 dw 或 db 較大時&#xff0c;(du)2,(db)2會較大&…

JAVA面試寶典 -《網絡編程核心:NIO 與 Netty 線程模型詳解》

網絡編程核心&#xff1a;NIO 與 Netty 線程模型詳解 文章目錄網絡編程核心&#xff1a;NIO 與 Netty 線程模型詳解一、傳統 BIO 模型&#xff1a;排隊買奶茶的阻塞模式 &#x1f964;1.1 專業解釋1.2 簡單點比喻1.3 簡單示例二、NIO 模型&#xff1a;智能叫號餐廳系統 &#x…

藍橋杯 第十六屆(2025)真題思路復盤解析

本文以洛谷平臺所提供的題目描述及評測數據為基礎進行講解。 前言&#xff1a;這是本人的藍橋杯試卷&#xff0c;大概排省一前40%的位置&#xff0c;實際上這屆題目偏難&#xff0c;我沒有做出太多的有效得分。我把當時的思路和現在學習的思路都復盤進來&#xff0c;希望給大家…

蘭頓螞蟻路徑lua測試

蘭頓螞蟻local p0 local x,y,z0,7,0 local function add() local result,id Block:getBlockID(x,y,z)if id1 thenBlock:destroyBlock(x,y,z,false) pp90 elseBlock:setBlockAll(x,y,z,1,0) pp-90 end x,zx-math.floor(0.5math.sin(math.rad(p))),z-math.floor(0.5math.cos(m…

【Axure RP】什么是Axure?Axure可以用來做什么?

【Axure RP】什么是Axure&#xff1f;Axure可以用來做什么&#xff1f; 目錄【Axure RP】什么是Axure&#xff1f;Axure可以用來做什么&#xff1f;Axure RP簡介Axure RP 是什么&#xff1f;Axure RP核心功能和應用場景Axure RP簡介 Axure RP 是什么&#xff1f; Axure RP 是一…

Java項目:基于SSM框架實現的暢玩北海旅游網站管理系統【ssm+B/S架構+源碼+數據庫+畢業論文】

摘 要 現代經濟快節奏發展以及不斷完善升級的信息化技術&#xff0c;讓傳統數據信息的管理升級為軟件存儲&#xff0c;歸納&#xff0c;集中處理數據信息的管理方式。本暢玩北海旅游網站就是在這樣的大環境下誕生&#xff0c;其可以幫助管理者在短時間內處理完畢龐大的數據信息…

NuxtJS中網絡請求模塊的封裝與最佳實戰

在網絡開發中&#xff0c;封裝一個簡潔、高效的網絡請求模塊對于項目的可維護性和擴展性至關重要。本文將詳細介紹如何在NuxtJS中封裝一個通用的網絡請求模塊&#xff0c;并結合最佳實踐來說明如何使用它來進行網絡請求。良好的代碼結構和封裝&#xff0c;不但結構清晰還能夠大…

云歸子批量混剪軟件批量剪輯軟件批量分割視頻更新記錄

www.yunguizi.com 優化顯卡硬件加速配置 ? 優化 2025年07月07日 版本 v1.1.6 優化顯卡硬件加速配置 修復了一些重要內容 &#x1f41b; 修復 2025年07月06日 版本 v1.1.6 修復了一些重要內容 重構讀寫機制 ? 優化 2025年07月06日 版本 v1.1.6 優化了一些重要內容&#xff1b;…