zoukankan      html  css  js  c++  java
  • Jetty 9 源码分析 Connector及Server类(一)

    本文的源码基于Jetty9,主要分析了Jetty 的Connector与Server类间在Jetty启动过程中的一些细节。
    Jetty9 对以前的Connector体系进行了重构, 结构与6和7都不同,原有的一些BIO类已经被抛弃。


    先看Server 构造函数

    public Server(@Name("port")int port)
    {
    this((ThreadPool)null);
    ServerConnector connector=new ServerConnector(this);
    connector.setPort(port);
    setConnectors(new Connector[]{connector});
    }

    将本身传入ServerConnector构造, 设置connector的port, 并将ServerConnector传入自身的
    Connector数组,保持引用。

    Server自身的Connectors数组变量,采用CopyOnWriteArrayList,保证可能的线程操作的安全。

    private final List<Connector> _connectors = new CopyOnWriteArrayList<>();

    Server启动类在Jetty.xml中定义,并设置线程池,Handler

    <Configure id="Server" class="org.eclipse.jetty.server.Server">

    ThreadPool是共享的, Connector与dispatch类都会用到。

    Server继承自HandlerWrapper, HandlerWrapper将handle代理给其装饰的类,即实际的Handler类,实现Decorator模式。
    继承关系如下:


    AbstractHandler
    |-AbstractHandlerContainer
      |-HandlerWrapper
        |-Server

    Server的启动方法是doStart(),该方法先调用上层doStart()方法,然后调用自身Connector数组的中的Connector类的start()方法。

    try
    {
    super.doStart();
    }
    
    for (Connector _connector : _connectors)
    {
    try
    {
    _connector.start();
    }
    catch (Throwable e)
    {
    mex.add(e);
    }
    }

    ServerConnector是Jetty9中主要的Connector实现,负责主要接入处理,此类主要的操作还有Java对接入连接的抽象Connection,
    Connection由Connector中设置的工厂类产生,如果没设置过,默认的工厂类是HttpConnectionFactory。
    Connector中还会与另一抽象Selector交互。

    描述了ServerConnector继承关系的类图:


    ServerConnector的继承层次如下:

    下面看一些具体点的代码:


    AbstractLifeCycle start() -> doStart(); 预留了doStart()方法供子类重写。
    |-ContainerLifeCycle doStart()
      |-AbstractConnector
        |-AbstractNetworkConnector doStart() ->open(); 设置了一个open方法供子类重写
          |-ServerConnector open(); 实现了open方法,打开ServerSocketChannel


    AbstractLifeCycle中start()的内容:

    try
    {
    if (_state == __STARTED || _state == __STARTING)
    return;
    setStarting();
    doStart();
    setStarted();
    }

    可看到此方法作为一个模板方法,将doStart()的实现留给子类重写,其自身的doStart()是一个空方法,这种用法在Jetty跟生命周期有关的类很多。

    Open方法的内容,隐藏部分不太重要的细节: 

    if (serverChannel == null)
    {
    serverChannel = ServerSocketChannel.open();
    
    InetSocketAddress bindAddress = getHost() == null ? new InetSocketAddress(getPort()) : new InetSocketAddress(getHost(), getPort());
    serverChannel.socket().bind(bindAddress, getAcceptQueueSize());
    serverChannel.socket().setReuseAddress(getReuseAddress());
    
    _localPort = serverChannel.socket().getLocalPort();
    if (_localPort <= 0)
    throw new IOException("Server channel not bound");
    
    addBean(serverChannel);
    }
    
    serverChannel.configureBlocking(true);
    addBean(serverChannel);
    
    _acceptChannel = serverChannel;

    这里的ServerSocketChannel使用的是阻塞模式,

    回到 AbstractNetworkConnector 的doStart中:

    protected void doStart() throws Exception
    {
    open();
    super.doStart();
    }

    方法继续调用了父类的doStart(), 那么再看父类AbstractConnector的doStart():

    protected void doStart() throws Exception
    {
    _defaultConnectionFactory = getConnectionFactory(_defaultProtocol);
    
    super.doStart();
    
    _stopping=new CountDownLatch(_acceptors.length);
    for (int i = 0; i < _acceptors.length; i++)
    getExecutor().execute(new Acceptor(i));
    
    }

    此方法设置的默认的ConnectionFactory, 另一个重要概念Acceptor类也是这里出现的。
    Acceptor是AbstractConnector的私有内部类,这里用的CountDownLatch是给doStop用的, stop中会计算这个CountDownLatch是否为空,
    不为空则会调用CountDownLatch.await等待, 知道Acceptor的线程都停掉才继续做stop的其他事情。
    Acceptor的数量在该类的构造方法中进行初始化,下面是片段:

    if (acceptors<=0)
    acceptors=Math.max(1,(Runtime.getRuntime().availableProcessors()) / 2);

    主要计算方式就是最少是1个,是否大于一个要根据CPU数量来,按CPU核心数量/2来计算Acceptor的数量。

  • 相关阅读:
    mysql CREATE USER
    ConvertHelper 通用类
    自定义属性
    为什么建议使用你LocalDateTime,而不是Date?
    使用IDEA插件Alibaba Cloud Toolkit工具一键部署本地应用到ECS服务器
    IDEA-SpringBoot项目设置热部署
    CentOS7中MySQL跨机器数据迁移
    Centos7 使用YUM安装Mariadb
    Linux下svn服务器迁移
    java dateutil工具类Date.add()
  • 原文地址:https://www.cnblogs.com/zhukunrong/p/3810562.html
Copyright © 2011-2022 走看看