websocket-cometd源碼閱讀-初始化(二)

常規配置

 <!-- CometD Servlet -->
  <servlet>
    <servlet-name>cometd</servlet-name>
<!--<1>--> <servlet-class>org.cometd.annotation.server.CometDServlet</servlet-class> <!--liqiang todo 600000--> <init-param> <param-name>maxProcessing</param-name> <param-value>600000</param-value> </init-param> <init-param> <param-name>timeout</param-name> <param-value>20000</param-value> </init-param> <init-param> <param-name>interval</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>maxInterval</param-name> <param-value>10000</param-value> </init-param> <init-param> <param-name>handshakeReconnect</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>maxLazyTimeout</param-name> <param-value>5000</param-value> </init-param> <init-param> <param-name>long-polling.multiSessionInterval</param-name> <param-value>2000</param-value> </init-param> <init-param> <param-name>services</param-name> <param-value>org.cometd.examples.ChatService</param-value> </init-param> <init-param> <param-name>ws.cometdURLMapping</param-name> <param-value>/cometd/*</param-value> </init-param> <!--容器啓動時調用init方法初始化 而不是第一次調用時--> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet>

<1>

通過ServletInit爲切入點進行初始化

org.cometd.server.CometDServlet#init

    @Override
    public void init() throws ServletException {
        try {
            boolean export = false;
            //可以通過ServletContext如果在別的地方自定義初始化 需要指定此值 比如自己根據spring容器初始化了
            _bayeux = (BayeuxServerImpl)getServletContext().getAttribute(BayeuxServer.ATTRIBUTE);
            if (_bayeux == null) {
                export = true;
                 //初始化
                _bayeux = newBayeuxServer();

                //這裏主要是設置Servlet參數到_bayeux 供後續初始化使用 
                // Transfer all servlet init parameters to the BayeuxServer implementation
                for (String initParamName : Collections.list(getInitParameterNames())) {
                    _bayeux.setOption(initParamName, getInitParameter(initParamName));
                }

                //添加ServletContext到_bayeux
                // Add the ServletContext to the options
                _bayeux.setOption(ServletContext.class.getName(), getServletContext());
            }

            //調用start進行組件初始化<2>
            _bayeux.start();

            if (export) {
                //設置到Attribute
                getServletContext().setAttribute(BayeuxServer.ATTRIBUTE, _bayeux);
            }
        } catch (Exception x) {
            throw new ServletException(x);
        }
    }

 <2>

org.cometd.server.BayeuxServerImpl#doStart

    @Override
    protected void doStart() throws Exception {
        //<3>初始化內置的渠道
        initializeMetaChannels();
        //<4>初始化消息序列化轉換器
        initializeJSONContext();
        //<5>初始化Transport
        initializeServerTransports();

        //如果線程池爲空 創建線程池
        if (_executor == null) {
            //<7>
            _executor = new MarkedReference<>(newExecutor(), true);
        }
        addBean(_executor.getReference());

        //如果Schedule爲空 創建Scheduler 
        if (_scheduler == null) {
            _scheduler = new MarkedReference<>(newScheduler(), true);
        }
        addBean(_scheduler.getReference());

        //配置獲得validateMessageFields  默認爲true 是否進行消息格式校驗
        _validation = getOption(VALIDATE_MESSAGE_FIELDS_OPTION, true);
        //配置獲得broadcastToPublisher 默認爲true 此消息是否廣播到發佈者,比如都訂閱了同一個渠道,是否廣播給自己
        _broadcastToPublisher = getOption(BROADCAST_TO_PUBLISHER_OPTION, true);

        super.doStart();

        long defaultSweepPeriod = 997;
        //獲得配置的sweepPeriodOption 會話掃描週期檢查會話是否需要移除 默認997  毫秒單位
        long sweepPeriodOption = getOption(SWEEP_PERIOD_OPTION, defaultSweepPeriod);
        if (sweepPeriodOption < 0) {
            sweepPeriodOption = defaultSweepPeriod;
        }
        long sweepPeriod = sweepPeriodOption;
        //開啓session檢查,檢查是否需要剔除
        schedule(new Runnable() {
            @Override
            public void run() {
                //並行執行asyncSweep的四個任務  執行完後指定週期後 開啓下一輪 實現了定時任務效果
                asyncSweep().whenComplete((r, x) -> schedule(this, sweepPeriod));
            }
        }, sweepPeriod);
    }

<3>

org.cometd.server.BayeuxServerImpl#initializeMetaChannels

    protected void initializeMetaChannels() {
        //握手<8>
        createChannelIfAbsent(Channel.META_HANDSHAKE);
        //續約連接
        createChannelIfAbsent(Channel.META_CONNECT);
        //訂閱渠道
        createChannelIfAbsent(Channel.META_SUBSCRIBE);
        //取消訂閱
        createChannelIfAbsent(Channel.META_UNSUBSCRIBE);
        //斷開連接
        createChannelIfAbsent(Channel.META_DISCONNECT);
    }

<4>

org.cometd.server.BayeuxServerImpl#initializeJSONContext

 protected void initializeJSONContext() throws Exception {
        //默認通過 option jsonContext去獲取
        Object option = getOption(AbstractServerTransport.JSON_CONTEXT_OPTION);
        if (option == null) {
            //未配置則獲取默認的
            _jsonContext = new JettyJSONContextServer();
        } else {
            //如果我們有配置的是class全名稱
            if (option instanceof String) {
                Class<?> jsonContextClass = Thread.currentThread().getContextClassLoader().loadClass((String)option);
                if (JSONContextServer.class.isAssignableFrom(jsonContextClass)) {
                    _jsonContext = (JSONContextServer)jsonContextClass.getConstructor().newInstance();
                } else {
                    throw new IllegalArgumentException("Invalid " + JSONContextServer.class.getName() + " implementation class");
                }
            } else if (option instanceof JSONContextServer) {//如果是context對象
                _jsonContext = (JSONContextServer)option;
            } else {
                throw new IllegalArgumentException("Invalid " + JSONContextServer.class.getName() + " implementation class");
            }
        }
        _options.put(AbstractServerTransport.JSON_CONTEXT_OPTION, _jsonContext);
    }

<5>

org.cometd.server.BayeuxServerImpl#initializeServerTransports

protected void initializeServerTransports() {
        if (_transports.isEmpty()) {
            //初始化Transport 沒重定義則創建默認 指定了則創建指定的 注:反射創建 會傳入bayeux
            String option = (String)getOption(TRANSPORTS_OPTION);
            if (option == null) {
                //未定義則初始化處理websocket 和長輪詢的Transport處理器 JSONP的處理器
                // Order is important, see #findHttpTransport()
                //<6>
                ServerTransport transport = newWebSocketTransport();
                if (transport != null) {
                    addTransport(transport);
                }
                addTransport(newJSONTransport());
                addTransport(new JSONPTransport(this));
            } else {
                //如果有進行類的全名稱配置 根據累的全名稱創建
                for (String className : option.split(",")) {
                    ServerTransport transport = newServerTransport(className.trim());
                    if (transport != null) {
                        addTransport(transport);
                    }
                }

                if (_transports.isEmpty()) {
                    throw new IllegalArgumentException("Option '" + TRANSPORTS_OPTION +
                            "' does not contain a valid list of server transport class names");
                }
            }
        }

        //如果沒有配置_allowedTransports 將transport加入到 _allowedTransports//liqiangtodo 暫時不曉得幹嘛的
        if (_allowedTransports.isEmpty()) {
            String option = (String)getOption(ALLOWED_TRANSPORTS_OPTION);
            if (option == null) {
                _allowedTransports.addAll(_transports.keySet());
            } else {
                for (String transportName : option.split(",")) {
                    if (_transports.containsKey(transportName)) {
                        _allowedTransports.add(transportName);
                    }
                }

                if (_allowedTransports.isEmpty()) {
                    throw new IllegalArgumentException("Option '" + ALLOWED_TRANSPORTS_OPTION +
                            "' does not contain at least one configured server transport name");
                }
            }
        }

        //逐個調用transport init方法完成Transport的初始化 Transport 內部的相關參數自定義配置可以通過Option拿到
        List<String> activeTransports = new ArrayList<>();
        for (String transportName : _allowedTransports) {
            ServerTransport serverTransport = getTransport(transportName);
            if (serverTransport instanceof AbstractServerTransport) {
                //調用init方法進行初始化
                ((AbstractServerTransport)serverTransport).init();
                //加入到已激活的transpor
                activeTransports.add(serverTransport.getName());
            }
        }
        if (_logger.isDebugEnabled()) {
            _logger.debug("Active transports: {}", activeTransports);
        }
    }

<6>

org.cometd.server.BayeuxServerImpl#newWebSocketTransport

  private ServerTransport newWebSocketTransport() {
        try {
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            //加載服務端websoket組件  websocket組件
            loader.loadClass("javax.websocket.server.ServerContainer");
            //初始化websoketTransport
            String transportClass = "org.cometd.server.websocket.javax.WebSocketTransport";
            ServerTransport transport = newServerTransport(transportClass);
            if (transport == null) {
                _logger.info("JSR 356 WebSocket classes available, but " + transportClass +
                        " unavailable: JSR 356 WebSocket transport disabled");
            }
            return transport;
        } catch (Exception x) {
            return null;
        }
    }

<7>

org.cometd.server.BayeuxServerImpl#newExecutor

private Executor newExecutor() {
        String name = _name + "-Executor";
        //默認線程大小爲128
        int maxThreads = (int)getOption(EXECUTOR_MAX_THREADS, 128);
        QueuedThreadPool executor = new QueuedThreadPool(maxThreads, 0);
        executor.setName(name);
        executor.setReservedThreads(0);
        return executor;
    }

 <8>

org.cometd.server.BayeuxServerImpl#createChannelIfAbsent

 @Override
    public MarkedReference<ServerChannel> createChannelIfAbsent(String channelName, Initializer... initializers) {
        ChannelId channelId;
        boolean initialized = false;
        //嘗試根據channelName獲取 判斷是否存在
        ServerChannelImpl channel = _channels.get(channelName);
        if (channel == null) {
            // Creating the ChannelId will also normalize the channelName.
            //嘗試通過處理過的channelId獲取
            channelId = new ChannelId(channelName);
            String id = channelId.getId();
            if (!id.equals(channelName)) {
                channelName = id;
                channel = _channels.get(channelName);
            }
        } else {
            channelId = channel.getChannelId();
        }

        //表示沒有被初始化
        if (channel == null) {
            //新建一個channel
            ServerChannelImpl candidate = new ServerChannelImpl(this, channelId);
            //放入_channels
            channel = _channels.putIfAbsent(channelName, candidate);
            if (channel == null) {
                // My candidate channel was added to the map, so I'd better initialize it

                channel = candidate;
                if (_logger.isDebugEnabled()) {
                    _logger.debug("Added channel {}", channel);
                }

                try {
                    //通知 Initializer實現 可以對ServerChannelImpl做自定義配置
                    for (Initializer initializer : initializers) {
                        notifyConfigureChannel(initializer, channel);
                    }

                    //調用listeners中ChannelListener的configureChannel方法可以對channel進行自定義配置
                    for (BayeuxServer.BayeuxServerListener listener : _listeners) {
                        if (listener instanceof ServerChannel.Initializer) {
                            notifyConfigureChannel((Initializer)listener, channel);
                        }
                    }
                } finally {
                    channel.initialized();
                }
                //調用listeners中ChannelListener的channelAdded表示已經被初始化
                for (BayeuxServer.BayeuxServerListener listener : _listeners) {
                    if (listener instanceof BayeuxServer.ChannelListener) {
                        notifyChannelAdded((ChannelListener)listener, channel);
                    }
                }

                initialized = true;
            }
        } else {
            channel.resetSweeperPasses();
            // Double check if the sweeper removed this channel between the check at the top and here.
            // This is not 100% fool proof (e.g. this thread is preempted long enough for the sweeper
            // to remove the channel, but the alternative is to have a global lock)
            _channels.putIfAbsent(channelName, channel);
        }
        // Another thread may add this channel concurrently, so wait until it is initialized
        channel.waitForInitialized();
        return new MarkedReference<>(channel, initialized);
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章