Bolt服务器的核心类是RpcServer,启动的时候调用父类AbstractRemotingServer的startup方法。

  1. com.alipay.remoting.AbstractRemotingServer#startup
  2. @Override
  3. public void startup() throws LifeCycleException {
  4. super.startup();
  5. try {
  6. doInit();
  7. logger.warn("Prepare to start server on port {} ", port);
  8. if (doStart()) {
  9. logger.warn("Server started on port {}", port);
  10. } else {
  11. logger.warn("Failed starting server on port {}", port);
  12. throw new LifeCycleException("Failed starting server on port: " + port);
  13. }
  14. } catch (Throwable t) {
  15. this.shutdown();// do stop to ensure close resources created during doInit()
  16. throw new IllegalStateException("ERROR: Failed to start the Server!", t);
  17. }
  18. }

这里主要做了三件事

  1. 调用父类的startup()方法设置状态为启动

    1. com.alipay.remoting.AbstractLifeCycle#startup
    2. @Override
    3. public void startup() throws LifeCycleException {
    4. if (isStarted.compareAndSet(false, true)) {
    5. return;
    6. }
    7. throw new LifeCycleException("this component has started");
    8. }
  2. 调用实现类的doInit()进行实际的初始化工作

    1. com.alipay.remoting.rpc.RpcServer#doInit
    2. @Override
    3. protected void doInit() {
    4. if (this.addressParser == null) {
    5. this.addressParser = new RpcAddressParser();
    6. }
    7. if (this.switches().isOn(GlobalSwitch.SERVER_MANAGE_CONNECTION_SWITCH)) {
    8. // in server side, do not care the connection service state, so use null instead of global switch
    9. ConnectionSelectStrategy connectionSelectStrategy = new RandomSelectStrategy(null);
    10. this.connectionManager = new DefaultServerConnectionManager(connectionSelectStrategy);
    11. this.connectionManager.startup();
    12. this.connectionEventHandler = new RpcConnectionEventHandler(switches());
    13. this.connectionEventHandler.setConnectionManager(this.connectionManager);
    14. this.connectionEventHandler.setConnectionEventListener(this.connectionEventListener);
    15. } else {
    16. this.connectionEventHandler = new ConnectionEventHandler(switches());
    17. this.connectionEventHandler.setConnectionEventListener(this.connectionEventListener);
    18. }
    19. initRpcRemoting();
    20. this.bootstrap = new ServerBootstrap();
    21. this.bootstrap.group(bossGroup, workerGroup)
    22. .channel(NettyEventLoopUtil.getServerSocketChannelClass())
    23. .option(ChannelOption.SO_BACKLOG, ConfigManager.tcp_so_backlog())
    24. .option(ChannelOption.SO_REUSEADDR, ConfigManager.tcp_so_reuseaddr())
    25. .childOption(ChannelOption.TCP_NODELAY, ConfigManager.tcp_nodelay())
    26. .childOption(ChannelOption.SO_KEEPALIVE, ConfigManager.tcp_so_keepalive());
    27. // set write buffer water mark
    28. initWriteBufferWaterMark();
    29. // init byte buf allocator
    30. if (ConfigManager.netty_buffer_pooled()) {
    31. this.bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
    32. .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
    33. } else {
    34. this.bootstrap.option(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT)
    35. .childOption(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT);
    36. }
    37. // enable trigger mode for epoll if need
    38. NettyEventLoopUtil.enableTriggeredMode(bootstrap);
    39. final boolean idleSwitch = ConfigManager.tcp_idle_switch();
    40. final int idleTime = ConfigManager.tcp_server_idle();
    41. final ChannelHandler serverIdleHandler = new ServerIdleHandler();
    42. final RpcHandler rpcHandler = new RpcHandler(true, this.userProcessors);
    43. this.bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
    44. @Override
    45. protected void initChannel(SocketChannel channel) {
    46. ChannelPipeline pipeline = channel.pipeline();
    47. pipeline.addLast("decoder", codec.newDecoder());
    48. pipeline.addLast("encoder", codec.newEncoder());
    49. if (idleSwitch) {
    50. pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, idleTime,
    51. TimeUnit.MILLISECONDS));
    52. pipeline.addLast("serverIdleHandler", serverIdleHandler);
    53. }
    54. pipeline.addLast("connectionEventHandler", connectionEventHandler);
    55. pipeline.addLast("handler", rpcHandler);
    56. createConnection(channel);
    57. }
    58. /**
    59. * create connection operation<br>
    60. * <ul>
    61. * <li>If flag manageConnection be true, use {@link DefaultConnectionManager} to add a new connection, meanwhile bind it with the channel.</li>
    62. * <li>If flag manageConnection be false, just create a new connection and bind it with the channel.</li>
    63. * </ul>
    64. */
    65. private void createConnection(SocketChannel channel) {
    66. Url url = addressParser.parse(RemotingUtil.parseRemoteAddress(channel));
    67. if (switches().isOn(GlobalSwitch.SERVER_MANAGE_CONNECTION_SWITCH)) {
    68. connectionManager.add(new Connection(channel, url), url.getUniqueKey());
    69. } else {
    70. new Connection(channel, url);
    71. }
    72. channel.pipeline().fireUserEventTriggered(ConnectionEventType.CONNECT);
    73. }
    74. });
    75. }

    这里的代码看似很复杂,其实主要是配置Netty服务器。Netty服务器的可配置选项通过ConfigManager来获取,Netty的业务处理在childHandler里面。

    1. protected void initChannel(SocketChannel channel) {
    2. ChannelPipeline pipeline = channel.pipeline();
    3. pipeline.addLast("decoder", codec.newDecoder());
    4. pipeline.addLast("encoder", codec.newEncoder());
    5. if (idleSwitch) {
    6. pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, idleTime,
    7. TimeUnit.MILLISECONDS));
    8. pipeline.addLast("serverIdleHandler", serverIdleHandler);
    9. }
    10. pipeline.addLast("connectionEventHandler", connectionEventHandler);
    11. pipeline.addLast("handler", rpcHandler);
    12. createConnection(channel);
    13. }

    初始化channel的方法里面有6个channelHandler

    1. decoder 解码器

    2. encoder 编码器

    3. idleStateHandler

      Netty自带的空闲处理器,用于触发IdleStateEvent。在这里配置了总空闲时间idleTime(默认值是90000),即idleTime时间内如果通道没有发生读写操作,将出发一个IdleStateEvent事件。

    4. serverIdleHandler

      配合idleStateHandler使用,用来处理IdleStateEvent。当触发该时间后,关闭客户端连接

      1. @Override
      2. public void userEventTriggered(final ChannelHandlerContext ctx, Object evt) throws Exception {
      3. if (evt instanceof IdleStateEvent) {
      4. try {
      5. logger.warn("Connection idle, close it from server side: {}",
      6. RemotingUtil.parseRemoteAddress(ctx.channel()));
      7. ctx.close();
      8. } catch (Exception e) {
      9. logger.warn("Exception caught when closing connection in ServerIdleHandler.", e);
      10. }
      11. } else {
      12. super.userEventTriggered(ctx, evt);
      13. }
      14. }
    5. connectionEventHandler

      connect事件处理器,类型由枚举类ConnectionEventType定义

      1. public enum ConnectionEventType {
      2. CONNECT, CLOSE, EXCEPTION;
      3. }
      • CONNECT

        connect事件在RpcServer.createConnection()方法里触发了一次

      • CLOSE

        close事件在连接断开时会触发

        1. com.alipay.remoting.ConnectionEventHandler
        2. @Override
        3. public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        4. String remoteAddress = RemotingUtil.parseRemoteAddress(ctx.channel());
        5. infoLog("Connection channel inactive: {}", remoteAddress);
        6. super.channelInactive(ctx);
        7. Attribute attr = ctx.channel().attr(Connection.CONNECTION);
        8. if (null != attr) {
        9. // add reconnect task
        10. if (this.globalSwitch != null
        11. && this.globalSwitch.isOn(GlobalSwitch.CONN_RECONNECT_SWITCH)) {
        12. Connection conn = (Connection) attr.get();
        13. if (reconnectManager != null) {
        14. reconnectManager.reconnect(conn.getUrl());
        15. }
        16. }
        17. // trigger close connection event
        18. onEvent((Connection) attr.get(), remoteAddress, ConnectionEventType.CLOSE);
        19. }
        20. }
      • EXCEPTION

        exception异常事件在源代码里面没有触发的地方,应该是预留的。

      无论是什么事件,最终都调用onEvent方法,转发给ConnectionEventListener,最终由用户自定义的ConnectionEventProcessor来处理具体逻辑

      1. com.alipay.remoting.ConnectionEventHandler#onEvent
      2. private void onEvent(final Connection conn, final String remoteAddress,
      3. final ConnectionEventType type) {
      4. if (this.eventListener != null) {
      5. this.eventExecutor.onEvent(new Runnable() {
      6. @Override
      7. public void run() {
      8. ConnectionEventHandler.this.eventListener.onEvent(type, remoteAddress, conn);
      9. }
      10. });
      11. }
      12. }
      13. com.alipay.remoting.ConnectionEventListener#onEvent
      14. public void onEvent(ConnectionEventType type, String remoteAddress, Connection connection) {
      15. List<ConnectionEventProcessor> processorList = this.processors.get(type);
      16. if (processorList != null) {
      17. for (ConnectionEventProcessor processor : processorList) {
      18. processor.onEvent(remoteAddress, connection);
      19. }
      20. }
      21. }
    6. handler

      具体业务处理器,注册类为RpcHandler,调用流程图如下

      对于客户端请求的处理交给UserProcessor, 可以调用RpcServer类的registerUserProcessor注册自定义的业务。

  3. 调用dostart启动服务器

    1. com.alipay.remoting.rpc.RpcServer#doStart
    2. @Override
    3. protected boolean doStart() throws InterruptedException {
    4. this.channelFuture = this.bootstrap.bind(new InetSocketAddress(ip(), port())).sync();
    5. return this.channelFuture.isSuccess();
    6. }

sofa-bolt源码阅读(1)-服务端的启动的更多相关文章

  1. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  2. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  3. Netty 4源码解析:服务端启动

    Netty 4源码解析:服务端启动 1.基础知识 1.1 Netty 4示例 因为Netty 5还处于测试版,所以选择了目前比较稳定的Netty 4作为学习对象.而且5.0的变化也不像4.0这么大,好 ...

  4. Netty源码阅读(一) ServerBootstrap启动

    Netty源码阅读(一) ServerBootstrap启动 转自我的Github Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速 ...

  5. TeamTalk源码分析之服务端描述

    TTServer(TeamTalk服务器端)主要包含了以下几种服务器: LoginServer (C++): 登录服务器,分配一个负载小的MsgServer给客户端使用 MsgServer (C++) ...

  6. netty4.1.6源码2-------创建服务端的channel

    1. netty在哪里调用jdk底层的socket去创建netty服务端的socket. 2. 在哪里accept连接. 服务端的启动: 1. 调用jdk底层的api去创建jdk的服务端的channe ...

  7. 4. 源码分析---SOFARPC服务端暴露

    服务端的示例 我们首先贴上我们的服务端的示例: public static void main(String[] args) { ServerConfig serverConfig = new Ser ...

  8. Netty源码分析之服务端启动过程

    一.首先来看一段服务端的示例代码: public class NettyTestServer { public void bind(int port) throws Exception{ EventL ...

  9. Spring Cloud系列(三):Eureka源码解析之服务端

    一.自动装配 1.根据自动装配原理(详见:Spring Boot系列(二):Spring Boot自动装配原理解析),找到spring-cloud-starter-netflix-eureka-ser ...

随机推荐

  1. 17)C++开始--命名空间

    命名空间:就是区分同一个名字,在不同的作用域的变量 代码展示 #include<iostream> namespace spaceA{ ; namespace spaceB{ struct ...

  2. EmailService

    package me.zhengjie.tools.service; import me.zhengjie.tools.domain.EmailConfig; import me.zhengjie.t ...

  3. 吴裕雄--天生自然python学习笔记:python 用pygame模块开发俄罗斯方块游戏

    俄罗斯方块游戏 多年前,游戏机中最流行的游戏就是“俄罗斯方块”了.时至今日,虽然网络 游戏日新月异 ,但“俄罗斯方块”这款小游戏仍在许多人心中 占有一席之地.本例中, 我们将亲手设计一个简单的俄罗斯方 ...

  4. VS2010 保护视力 背景色设置

    vs2010——工具——选项---环境——字体和颜色——纯文本——项背景色——自定义 色调:88 饱和度:92 亮度:209

  5. springboot shiro ehcache redis 简单使用

    引入相关pom <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  6. 02-信贷路由项目rose框架拆分dubbo

    项目架构和 rose 框架搭建见  https://www.cnblogs.com/yuanpeng-java/p/9835984.html 1.dubbo 框架架构及组成 2.注册中心安装及配置 h ...

  7. maven setting.xml说明

    <?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...

  8. android选择器汇总、仿最美应用、通用课程表、卡片动画、智能厨房、阅读客户端等源码

    Android精选源码 android各种 选择器 汇总源码 高仿最美应用项目源码 android通用型课程表效果源码 android实现关键字变色 Android ViewPager卡片视差.拖拽及 ...

  9. django框架基础-ORM基础-长期维护

    ###############    ORM介绍  ################ """ ORM简介: ORM 全拼Object-Relation Mapping. ...

  10. Markdown 内嵌 HTML 语法

    Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式.Markdown内嵌HTML,本文总结了一些常用的HTML标记用于扩展Markdow ...