环境
JDK的最低版本是8
Ubuntu 18
Spring Boot 2.1.0.RELEASE
底层使用OpenSLL
代码
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<exclusions>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty-tcnative-boringssl-static -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.19.Final</version>
</dependency>
</dependencies>
Http2App.java
@SpringBootApplication
public class Http2App {
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(Http2App.class)
.web(WebApplicationType.REACTIVE)
.run(args);
}
}
服务器启动
reactor.netty.tcp.TcpServerBind类的bind方法初始化SSL环境。
通过reactor.netty.channel.BootstrapHandlers类的finalizeHandler方法绑定初始handler。
最重要的handler是io.netty.handler.ssl.SslHandler。
它的主要功能是提供对SSL、TLS和StartTLS支持:
- 开始握手
- 握手,一旦开始以后就是自动的
- 关闭SSL session(向对端发送close_notify消息),SSL session关闭以后就不可用了,你得增加新的
- 重新开始一个SSL session,你要先在ChannelPipeline里删除已经关闭的SslHandler。然后再插入一个带有SSLEngine的SslHandler,然后开始握手
- 实现StartTLS。StartTLS一般分三步:
- 客户端发送StartTLS请求
- 服务器发送StartTLS响应
- 客户端开始SSL握手
服务器启动的时候,reactor.netty.http.server.HttpServerBind类apply方法,还完成了Http1OrH2Initializer的初始化工作。
return BootstrapHandlers.updateConfiguration(b,
NettyPipeline.HttpInitializer,
new Http1OrH2Initializer(conf.decoder.maxInitialLineLength,
conf.decoder.maxHeaderSize,
conf.decoder.maxChunkSize,
conf.decoder.validateHeaders,
conf.decoder.initialBufferSize,
conf.minCompressionSize,
compressPredicate(conf.compressPredicate, conf.minCompressionSize),
conf.forwarded,
conf.cookieEncoder,
conf.cookieDecoder));
注册了reactor.netty.http.server.HttpServerBind$Http1OrH2Codec
Http1OrH2Codec最终注册了流处理器Http2StreamBridgeHandler和Http2StreamFrameToHttpObjectCodec。
增加sslHandler
reactor.netty.tcp.SslProvider$SslSupportConsumer类的accept方法生成sslHandler
sslHandler = sslProvider.getSslContext().newHandler(channel.alloc());
上面的方法,调用的是io.netty.handler.ssl.ReferenceCountedOpenSslContext类的下面的方法。其中,jdkCompatibilityMode是false
@Override
protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
return new SslHandler(newEngine0(alloc, null, -1, false), startTls);
}
握手过程
具体的通信过程,由OpenSSL负责。netty-tcnative-boringssl-static主要通过io.netty.internal.tcnative.SSL类完成原生调用。
握手成功,由reactor.netty.tcp.SslProvider$SslReadHandler类处理SslHandshakeCompletionEvent事件。
if (handshake.isSuccess()) {
ctx.fireChannelActive();
}
else {
ctx.fireExceptionCaught(handshake.cause());
}
执行reactor.netty.http.server.HttpServerBind$Http1OrH2Codec类的configurePipeline方法。
p.addLast(NettyPipeline.HttpCodec, http2MultiplexCodecBuilder.build());
请求处理
reactor.netty.http.server.Http2StreamBridgeHandler类的channelRead方法处理Http2HeadersFrame消息。
reactor.netty.http.server.HttpToH2Operations类的onInboundNext方法,处理Http2DataFrame和Http2HeadersFrame消息。
reactor.netty.http.server.HttpServerOperations类的onInboundNext方法处理HttpRequest和HttpContent消息。