文章目录
- HttpObjectAggregator源码
-
- HttpObject类继承关系
- MessageToMessageDecoder
- MessageAggregator
-
- 属性
- 构造方法
- [acceptInboundMessage(Object msg)](#acceptInboundMessage(Object msg))
- decode
-
- [newContinueResponse(S start, int maxContentLength, ChannelPipeline pipeline)](#newContinueResponse(S start, int maxContentLength, ChannelPipeline pipeline))
- closeAfterContinueResponse
- ignoreContentAfterContinueResponse
- invokeHandleOversizedMessage
- beginAggregation
HttpObjectAggregator源码
HttpObject类继承关系

MessageToMessageDecoder
MessageToMessageDecoder<I> 继承自 ChannelInboundHandlerAdapter,它用于将1种消息转为另外一类的消息。
acceptInboundMessage方法用于判断传过来的msg是否是指定的泛型,如果msg是指定的泛型,则交给decode(ChannelHandlerContext ctx, I msg, List<Object> out)方法去做解码,该解码方法由子类自行实现;如果不是指定的泛型,则直接添加到out中;
在channelRead方法的最后面,遍历out,遍历添加至out的消息,传递给后面的入站处理器。
java
public abstract class MessageToMessageDecoder<I> extends ChannelInboundHandlerAdapter {
private final TypeParameterMatcher matcher;
protected MessageToMessageDecoder() {
matcher = TypeParameterMatcher.find(this, MessageToMessageDecoder.class, "I");
}
protected MessageToMessageDecoder(Class<? extends I> inboundMessageType) {
matcher = TypeParameterMatcher.get(inboundMessageType);
}
public boolean acceptInboundMessage(Object msg) throws Exception {
return matcher.match(msg);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
CodecOutputList out = CodecOutputList.newInstance();
try {
// acceptInboundMessage方法用于判断传过来的msg是否是指定的泛型
if (acceptInboundMessage(msg)) {
I cast = (I) msg;
try {
// 如果msg是指定的泛型,
// 则交给`decode(ChannelHandlerContext ctx, I msg, List<Object> out)`方法去做解码
// 该解码方法由子类自行实现
decode(ctx, cast, out);
} finally {
ReferenceCountUtil.release(cast);
}
} else {
out.add(msg);
}
} catch (DecoderException e) {
throw e;
} catch (Exception e) {
throw new DecoderException(e);
} finally {
try {
int size = out.size();
// 遍历out,遍历添加至out的消息,传递给后面的入站处理器
for (int i = 0; i < size; i++) {
ctx.fireChannelRead(out.getUnsafe(i));
}
} finally {
out.recycle();
}
}
}
protected abstract void decode(ChannelHandlerContext ctx, I msg, List<Object> out);
}
MessageAggregator
先看类声明MessageAggregator<I, S, C extends ByteBufHolder, O extends ByteBufHolder> extends MessageToMessageDecoder<I>
I - 起始消息和内容消息 所属类型,如HttpObject;
S - 起始消息 所属类型,如 HttpMessage;
C - 内容消息 所属类型,如 HttpContent;
O - 完整消息 所属类型,如 FullHttpMessage;
属性
java
// 消息内容最大长度
private final int maxContentLength;
// 当前正在处理的消息
private O currentMessage;
// 是否处理过长消息
private boolean handlingOversizedMessage;
// 最多允许的子ByteBuf的数量
private int maxCumulationBufferComponents = 1024;
// 当前handler对应的ChannelHandlerContext
private ChannelHandlerContext ctx;
private ChannelFutureListener continueResponseWriteListener;
// 当前是否正在聚合,初始化为false
private boolean aggregating;
构造方法
构造方法就是传入最大允许的内容长度
java
protected MessageAggregator(int maxContentLength) {
validateMaxContentLength(maxContentLength);
this.maxContentLength = maxContentLength;
}
protected MessageAggregator(int maxContentLength, Class<? extends I> inboundMessageType) {
super(inboundMessageType);
validateMaxContentLength(maxContentLength);
this.maxContentLength = maxContentLength;
}
acceptInboundMessage(Object msg)
根据前面MessageToMessageDecoder类中acceptInboundMessage方法中,当msg是指定类型时,交给子类的decode去作解码。子类MessageAggregator重写了acceptInboundMessage,如下:
java
@Override
public boolean acceptInboundMessage(Object msg) throws Exception {
// 首先调用父类的acceptInboundMessage方法,表示如果不是指定的泛型,直接返回false。
// 返回false后,将直接添加到out中,然后传给后面的入站处理器,不会进入到后面的聚合操作。
if (!super.acceptInboundMessage(msg)) {
return false;
}
// 走到这里,说明msg是指定泛型类型的消息
I in = (I) msg;
// 这里的isAggregated是个抽象方法,表示in是否是已经聚合好了的消息
// 比如子类HttpObjectAggregator判断in是FullHttpMessage类型,那就表示不需要聚合操作了,
// 直接传给后面的入站处理器就行了
if (isAggregated(in)) {
return false;
}
// 这里的isStartMessage是个抽象方法,表示in是否是起始消息
// 比如子类HttpObjectAggregator判断in是HttpMessage类型,那就表示要开始聚合消息了
// 因为Http消息是先来1个包含消息头和协议版本的HttpMessage消息,后面再跟HttpContent内容的
if (isStartMessage(in)) {
aggregating = true;
return true;
}
// 这里的isContentMessage是个抽象方法,表示in是否是内容消息
// 比如子类HttpObjectAggregator判断in是HttpContent类型
// 必须是先有了HttpMessage消息后,后续来HttpContent消息,后续的HttpContent才会交给decode方法去作聚合处理
else if (aggregating && isContentMessage(in)) {
return true;
}
// 其它情况一律不做decode,直接传给后面的入站处理器
return false;
}
decode
java
@Override
protected void decode(final ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception {
// 表示必须是先有了HttpMessage之后, 进入到聚合,先进入HttpMessage,后续跟HttpContent消息
assert aggregating;
// 如果msg是起始消息,
// 即msg是HttpMessage类型(协议版本和请求头)
if (isStartMessage(msg)) {
// 先初始化 正在处理过长消息 为 false
handlingOversizedMessage = false;
// 如果currentMessage不为null, 则释放原来聚合好的消息, 并将它置为null, 然后抛出异常
if (currentMessage != null) {
currentMessage.release();
currentMessage = null;
throw new MessageAggregationException();
}
S m = (S) msg;
// 根据 HttpMessage 确定是否要写入1个 continueResponse,
// 如果要写入,则返回1个不为null的FullHttpResponse响应对象;如果不要写入,则返回null
// 用于处理客户端请求发送Expect: 100-continue时的场景, 可能返回null, 413的FullHttpResponse, 417的FullHttpResponse, 100的FullHttpResponse
Object continueResponse = newContinueResponse(m, maxContentLength, ctx.pipeline());
// 需要写出 continueReponse(FullHttpResponse类型)
if (continueResponse != null) {
// 第一次处理到时, 才初始化listener, 并缓存下来这个 continueResponse写监听器
ChannelFutureListener listener = continueResponseWriteListener;
if (listener == null) {
continueResponseWriteListener = listener = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
if (!future.isSuccess()) {
// 如果写出 continueReponse 失败, 则触发异常事件传播
ctx.fireExceptionCaught(future.cause());
}
}
};
}
// 调用子类方法, 判断 在写完 continueResponse 之后, 是否需要关闭
boolean closeAfterWrite = closeAfterContinueResponse(continueResponse);
// 调用子类方法, 返回是否忽略后面的内容, 标记handlingOversizedMessage
// HttpObjectAggregator判断continueResponse如果是4xx响应状态码, 则标记handlingOversizedMessage为true
handlingOversizedMessage = ignoreContentAfterContinueResponse(continueResponse);
// 异步写出continueResponse
// 并添加监听器, 当写出失败时, 传播异常事件
final ChannelFuture future = ctx.writeAndFlush(continueResponse).addListener(listener);
// 如果需要写完之后关闭channel, 则添加监听器, 在写操作完成之后, 执行关闭操作, 并结束当前方法
if (closeAfterWrite) {
future.addListener(ChannelFutureListener.CLOSE);
return;
}
// 如果 handlingOversizedMessage 为 true, 结束当前方法
// (即返回给客户端的响应状态码是417/413)
if (handlingOversizedMessage) {
return;
}
}
// 如果 continueResponse 是null,
// 并且 content-length请求头存在且大于maxContentLength
else if (isContentLengthInvalid(m, maxContentLength)) {
// 处理过长消息, 返回413, 看是否需要关闭连接
invokeHandleOversizedMessage(ctx, m);
// 结束当前方法
return;
}
// 正常处理了expect:100-continue 或者 没有expect头并且消息没有过长
// 如果请求头解码有错误, 也需要聚合起来传递给后面的入站处理器
if (m instanceof DecoderResultProvider && !((DecoderResultProvider) m).decoderResult().isSuccess()) {
// 聚合起来的对象
O aggregated;
// 如果 m 也实现了ByteBufHolder(一般不会走这个分支吧), 则把内容聚合起来
if (m instanceof ByteBufHolder) {
// 开始聚合(由子类实现)
aggregated = beginAggregation(m, ((ByteBufHolder) m).content().retain());
} else {
// 如果 m 没实现ByteBufHolder, 则聚合1个空的内容,开始聚合(由子类实现)
aggregated = beginAggregation(m, EMPTY_BUFFER);
}
// 完成聚合, 将aggregating置为false, 如果未设置content-length, 则会设置进去
finishAggregation0(aggregated);
// 传递给后面的入站处理
out.add(aggregated);
// 结束当前方法
return;
}
// 说明前面解码正常
// 初始化用来存储消息体内容的ByteBuf容器
CompositeByteBuf content = ctx.alloc().compositeBuffer(maxCumulationBufferComponents);
// 如果 m 实现了 ByteBufHolder 接口, 则将内容作组合到 消息体 中
if (m instanceof ByteBufHolder) {
appendPartialContent(content, ((ByteBufHolder) m).content());
}
// 开始聚合, 创建 AggregatedFullHttpRequest 或 AggregatedFullHttpResponse
// 并初始化 currentMessage 属性, 它表示当前正在处理的消息, 后续的消息内容会组合到此消息中
currentMessage = beginAggregation(m, content);
} else if (isContentMessage(msg)) { // 如果msg实现了HttpContent接口
// 如果 currentMessage 是null, 则忽略(丢弃), 可以结束当前方法, 直到下一次的请求或响应
if (currentMessage == null) {
return;
}
// 用于存储当前收到的消息内容
CompositeByteBuf content = (CompositeByteBuf) currentMessage.content();
// 当前的消息内容
final C m = (C) msg;
// 如果已经收到的消息内容 加上 当前收到的消息内容的 长度 超过了最大允许的内容长度
if (content.readableBytes() > maxContentLength - m.content().readableBytes()) {
S s = (S) currentMessage;
// 处理过长消息, 返回413, 看是否需要关闭连接
invokeHandleOversizedMessage(ctx, s);
// 结束当前方法
return;
}
// 将当前收到的消息内容组合到消息体中
appendPartialContent(content, m.content());
// 给子类1个机会去处理
// 子类HttpObjectAggregator会判断m如果是LastHttpContent, 则会将trailingHeaders都设置给currentMessage
aggregate(currentMessage, m);
// 判断当前收到的消息内容是否是最后一块消息内容了
final boolean last;
// 如果当前收到的消息内容 实现了DecoderResultProvider
if (m instanceof DecoderResultProvider) {
// 先看解码结果是否是成功的,
DecoderResult decoderResult = ((DecoderResultProvider) m).decoderResult();
// 如果解码不成功
if (!decoderResult.isSuccess()) {
// 把失败的原因记录给当前聚合的消息currentMessage
if (currentMessage instanceof DecoderResultProvider) {
((DecoderResultProvider) currentMessage).setDecoderResult(
DecoderResult.failure(decoderResult.cause()));
}
// 并标记是最后一块消息了, 因为已经失败了
last = true;
} else {
// 如果解码成功, 则判断 当前收到的消息是否是LastHttpContent消息
last = isLastContentMessage(m);
}
} else {
// 判断 当前收到的消息是否是LastHttpContent消息
last = isLastContentMessage(m);
}
// 如果是最后一块消息内容 或者 解码某块内容时错误
if (last) {
// 完成聚合, 将aggregating置为false, 如果未设置content-length, 则会设置进去
finishAggregation0(currentMessage);
// 将当前消息传给后续的入站处理器
out.add(currentMessage);
// 处理以上后, currentMessage重新置为null, 可以处理下一个请求或响应了
currentMessage = null;
}
} else {
throw new MessageAggregationException();
}
}
newContinueResponse(S start, int maxContentLength, ChannelPipeline pipeline)
HttpObjectAggregator#newContinueResponse实现如下:
java
@Override
protected Object newContinueResponse(HttpMessage start, int maxContentLength, ChannelPipeline pipeline) {
// 处理起始消息的expect请求头
Object response = continueResponse(start, maxContentLength, pipeline);
// 如果处理了expect请求头,就移除掉expect请求头
if (response != null) {
start.headers().remove(EXPECT);
}
// 返回response
return response;
}
private static Object continueResponse(HttpMessage start,
int maxContentLength,
ChannelPipeline pipeline) {
// 如果 起始消息 是 HttpRequest类型, 并且 协议版本是1.1及以上, 则返回false
// 否则 expect请求头不为空 并且 该请求头的值 不是 continue, 则返回true, 其它情况返回false
// (表示不支持expectation请求头的情况)
if (HttpUtil.isUnsupportedExpectation(start)) {
// 触发自定义事件传播 HttpExpectationFailedEvent.INSTANCE
pipeline.fireUserEventTriggered(HttpExpectationFailedEvent.INSTANCE);
// 返回 417 状态码(因为这个对象是公用的,所以每次用都要retained)
return EXPECTATION_FAILED.retainedDuplicate();
} else if (HttpUtil.is100ContinueExpected(start)) {
// 如果 起始消息 是 HttpRequest类型, 并且 协议版本是1.1及以上
// 并且 expect请求头 存在, 且值为 100-continue
// 获取 content-length 请求头的值, 如果有的话, 并且它不超过maxContentLength,
// 则返回 100 状态码, 表示可以继续上传
if (getContentLength(start, -1L) <= maxContentLength) {
return CONTINUE.retainedDuplicate();
}
// 表示内容超过了maxContentLength允许的长度
// 触发自定义事件传播 HttpExpectationFailedEvent.INSTANCE
pipeline.fireUserEventTriggered(HttpExpectationFailedEvent.INSTANCE);
// 返回 413 状态码
return TOO_LARGE.retainedDuplicate();
}
return null;
}
closeAfterContinueResponse
HttpObjectAggregator#newContinueResponse实现如下:
java
@Override
protected boolean closeAfterContinueResponse(Object msg) {
// 如果配置的 closeOnExpectationFailed 为true(默认是false), 并且响应状态码是4xx, 则返回true
// 其它情况, 则返回false
return closeOnExpectationFailed && ignoreContentAfterContinueResponse(msg);
}
ignoreContentAfterContinueResponse
HttpObjectAggregator#ignoreContentAfterContinueResponse实现如下:
java
@Override
protected boolean ignoreContentAfterContinueResponse(Object msg) {
if (msg instanceof HttpResponse) {
final HttpResponse httpResponse = (HttpResponse) msg;
// 响应状态码是 4xx, 即客户端错误
return httpResponse.status().codeClass().equals(HttpStatusClass.CLIENT_ERROR);
}
return false;
}
invokeHandleOversizedMessage
MessageAggregator#invokeHandleOversizedMessage实现如下
java
private void invokeHandleOversizedMessage(ChannelHandlerContext ctx, S oversized) throws Exception {
// 标记 handlingOversizedMessage 为true
handlingOversizedMessage = true;
// 当前正在聚合的消息 的引用 置为null
currentMessage = null;
try {
// 处理过长消息
handleOversizedMessage(ctx, oversized);
} finally {
// 释放 oversized
ReferenceCountUtil.release(oversized);
}
}
protected void handleOversizedMessage(ChannelHandlerContext ctx,
S oversized) throws Exception {
// 默认实现 是 传播 TooLongFrameException异常事件
ctx.fireExceptionCaught(
new TooLongFrameException("content length exceeded "
+ maxContentLength() + " bytes."));
}
handleOversizedMessage
HttpObjectAggregator#handleOversizedMessage 重写了该方法
java
@Override
protected void handleOversizedMessage(final ChannelHandlerContext ctx,
HttpMessage oversized) throws Exception {
// 如果是客户端发过来的请求太大了
if (oversized instanceof HttpRequest) {
// 如果过长消息是FullHttpMessage类型 或者 (那就是HttpRequest或HttpResponse咯)expect头不是100-contine的请求头情况并且connection头不是keep-alive
if (oversized instanceof FullHttpMessage
|| !HttpUtil.is100ContinueExpected(oversized) && !HttpUtil.isKeepAlive(oversized)
) {
// 异步写给客户端1个413的响应状态码
ChannelFuture future = ctx.writeAndFlush(TOO_LARGE_CLOSE.retainedDuplicate());
// 写完413状态码后,关闭连接
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());
}
ctx.close();
}
});
} else {
// 写完413状态码后,如果写入操作没有成功则关闭连接
ctx.writeAndFlush(TOO_LARGE.retainedDuplicate()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());
ctx.close();
}
}
});
}
} else if (oversized instanceof HttpResponse) { // 如果是服务端发过来的响应太大了
// 关闭连接
ctx.close();
// 排除内容过长的异常
throw new TooLongHttpContentException("Response entity too large: " + oversized);
} else {
// 其它类型的消息不支持
throw new IllegalStateException();
}
}
beginAggregation
HttpObjectAggregator#beginAggregation
java
@Override
protected FullHttpMessage beginAggregation(HttpMessage start, ByteBuf content) throws Exception {
// start消息一定不能是 FullHttpMessage,都已经完成了,还咋聚合
assert !(start instanceof FullHttpMessage);
// 这里传入false,表示移除掉start消息中的transfer-encoding消息头的 chunked值
HttpUtil.setTransferEncodingChunked(start, false);
AggregatedFullHttpMessage ret;
if (start instanceof HttpRequest) {
// 聚合, 传入start,content 和 trailingHeaders
ret = new AggregatedFullHttpRequest((HttpRequest) start, content, null);
} else if (start instanceof HttpResponse) {
// 聚合, 传入start,content 和 trailingHeaders
ret = new AggregatedFullHttpResponse((HttpResponse) start, content, null);
} else {
// 不支持其它类型
throw new Error();
}
return ret;
}