源码分析Dubbo网络通信篇NettyServer、HeaderExchangeServer

1.1.1 AbstractServer构造方法

public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {

super(url, handler); // @1

localAddress = getUrl().toInetSocketAddress(); // @2

String bindIp = getUrl().getParameter(Constants.BIND_IP_KEY, getUrl().getHost());

int bindPort = getUrl().getParameter(Constants.BIND_PORT_KEY, getUrl().getPort());

if (url.getParameter(Constants.ANYHOST_KEY, false) || NetUtils.isInvalidLocalHost(bindIp)) {

bindIp = NetUtils.ANYHOST;

}

bindAddress = new InetSocketAddress(bindIp, bindPort); // @3

this.accepts = url.getParameter(Constants.ACCEPTS_KEY, Constants.DEFAULT_ACCEPTS);

this.idleTimeout = url.getParameter(Constants.IDLE_TIMEOUT_KEY, Constants.DEFAULT_IDLE_TIMEOUT); // @4

try {

doOpen(); // @5

if (logger.isInfoEnabled()) {

logger.info("Start " + getClass().getSimpleName() + " bind " + getBindAddress() + ", export " + getLocalAddress());

}

} catch (Throwable t) {

throw new RemotingException(url.toInetSocketAddress(), null, "Failed to bind " + getClass().getSimpleName()

  • " on " + getLocalAddress() + ", cause: " + t.getMessage(), t);

}

//fixme replace this with better method

DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();

executor = (ExecutorService) dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY, Integer.toString(url.getPort()));

}

代码@1:调用父类的构造方法,主要初始化AbstractPeer(channelHandler、url)和AbstractEndpoint(codec2、timeout、idleTimeout )

代码@2:根据URL中的host与端口,创建localAddress。

代码@3:如果配置了< dubbo:parameter key = “bind.ip” value = “”/> 与 < dubbo:parameter key = “bind.port” />,则用该IP与端口创建bindAddress,通常用于多网卡,如果未配置,bindAddress与 localAddress绑定的IP与端口一样。

代码@4:初始化accepts与idleTimeout ,这两个参数未被其他地方使用。

代码@5,调用doOpen方法,正式在相应端口建立网络监听。

1.2、源码分析NettyServer#doOpen

protected void doOpen() throws Throwable {

NettyHelper.setNettyLoggerFactory();

bootstrap = new ServerBootstrap(); // @1

bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory(“NettyServerBoss”, true)); // @2

workerGroup = new NioEventLoopGroup(getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),

new DefaultThreadFactory(“NettyServerWorker”, true)); // @3

final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this); // @4

channels = nettyServerHandler.getChannels();

bootstrap.group(bossGroup, workerGroup) // @5

.channel(NioServerSocketChannel.class)

.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)

.childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)

.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)

.childHandler(new ChannelInitializer() {

@Override

protected void 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 initChannel(NioSocketChannel ch) throws Exception {

NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);

ch.pipeline()//.addLast(“logging”,new LoggingHandler(LogLevel.INFO))//for debug

.addLast(“decoder”, adapter.getDecoder())

.addLast(“encoder”, adapter.getEncoder())

.addLast(“handler”, nettyServerHandler);

}

});

// bind

ChannelFuture channelFuture = bootstrap.bind(getBindAddress()); // @6

channelFuture.syncUninterruptibly();

channel = channelFuture.channel();

}

代码@1:创建Netty服务端启动帮助类ServerBootstrap.

代码@2:创建服务端Boss线程,线程名:.NettyServerBoss,主要负责客户端的连接事件,主从多Reactor线程模型中的主线程(连接事件)。

代码@3:创建服务端Work线程组,线程名:NettyServerWorker-序号,线程个数取自参数:iothreads,默认为(CPU核数+1)与32取小值,顾名思义,IO线程数,主要处理读写事件,编码、解码都在IO线程中完成。

代码@4:创建用户Handler,这里是NettyServerHandler。

代码@5:Netty启动的常规写法,关注如下内容:

addLast(“decoder”, adapter.getDecoder()) : 添加解码器

addLast(“encoder”, adapter.getEncoder()) :添加编码器

addLast(“handler”, nettyServerHandler) :添加业务Handler。

这里简单介绍一下流程:

1、客户端建立与服务端连接,此时Boss线程的连接事件触发,建立TCP连接,并向IO线程注册该通道(Channel0)的读事件。

2、当客户端向服务端发送请求消息后,IO线程中的读事件触发,会首先调用adapter.getDecoder() 根据对应的请求协议(例如dubbo)从二进制流中解码出一个完整的请求对象,然后传入到业务handler,例如nettyServerHandler,执行相应的事件方法,例如recive方法。

3、当服务端向Channel写入响应结果时,首先编码器会按照协议编码成二进制流,供客户端解码。、

如果对Netty想深入学习的话,请移步到作者的《源码分析Netty系列》https://blog.csdn.net/prestigeding/article/details/53977445

2、HeaderExchangeServer

根据Dubbo服务端初始化流程,我们可知,Dubbo为了封装各种不同的网络实现客户端(netty、mina)等,映入了Exchangers层,通用存在ExchangeServer,其实现Server并内部持有具体的Server实现端,例如NettyServer。

这里写图片描述

接下来,我们重点来关注一下HeaderExchangeServer.

核心属性如下:

  • ScheduledExecutorService scheduled:心跳线程数,线程名称前缀,dubbo-remoting-server-heartbeat-thread-序号

  • private final Server server:具体的Server实现类,例如NettyServer。

  • private ScheduledFuture< ?> heartbeatTimer:心跳调度Future,可以通过future取消心跳等动作。

  • private int heartbeat:心跳间隔时间

  • private int heartbeatTimeout:心跳超时时间,至少为heartbeat的两倍

2.1 构造函数

public HeaderExchangeServer(Server server) {

if (server == null) {

throw new IllegalArgumentException(“server == null”);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值