文档章节

Jetty源码-Server-Connector

robin-yao
 robin-yao
发布于 2015/04/21 22:55
字数 982
阅读 103
收藏 0

    Jetty Server两个重要的概念一个是Handler,一个是Connector。 我们在内嵌Jetty启动应用时往往会通过WebAppContext来设置上下文,WebAppContext就是一个Handler,我们可以通过Server.setHandler()来赋值我们的上下文。本文主要介绍Connector。它的抽象实现类是AbstractConnector,然后ServerConnector继承了AbstractConnector,这也是重点要介绍的两个类。连接器故名思议主要是用来处理各种类型的请求包括HTTP, HTTP/2 ,WebSocket等等。Jetty 9采用NIO来处理请求,去掉了BIO模块。

    下边先贴出一段实用的Jetty内嵌启动代码,方便我们理解Handler和Connector。采用的是9.3版本的jetty jar

/** jetty pom
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-server</artifactId>
    <version>9.3.0.M0</version>
</dependency>
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-webapp</artifactId>
    <version>9.3.0.M0</version>
</dependency>
**/

//内嵌代码------------------

Server server = new Server();
// connector
ServerConnector connector = new ServerConnector(server);
connector.setPort(port);
server.setConnectors(new Connector[] { connector });
//context
WebAppContext context = new WebAppContext();
context.setContextPath("/");
//设定webapp,具体的路径根据自己应用来调整
context.setResourceBase("./src/main/webapp");
context.setClassLoader(Thread.currentThread().getContextClassLoader());
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
server.join();
//-----------------------------------------

    AbstractConnector是Connector的实现类,它提供了ConnectionFactory机制来创建各种协议(HTTP, SSL)的实例。AbstractConnector封装了几个重要的属性:

         Executor:线程池,用来处理接收的连接;

         Scheduler:用来监视连接的超时;

         ByteBufferPool:ByteBuffer缓冲池,减少对ByteBuffer的创建开销,循环利用ByteBuffer;

         ConnectionFactory: 创建各种协议的工厂,包含 SslConnectionFactory,HttpConnectionFactory等等;

         Acceptors:来创建接收器的,监听端口过来的请求。AbstractConnector里面 有个 final Thread[] _acceptors  变量 ,这个变量是个线程数组,个数代表你需要创建并发的接收器,多个接收器调用同一个ServerSocketChannel实例上的accept方法,来实现高效的接收请求。AbstractConnector在doStart方法中初始化Acceptor。

protected void doStart() throws Exception
{
    _defaultConnectionFactory = getConnectionFactory(_defaultProtocol);
 
    _stopping=new CountDownLatch(_acceptors.length);
    for (int i = 0; i < _acceptors.length; i++)
    {
        Acceptor a = new Acceptor(i);
        addBean(a);
        getExecutor().execute(a);
        //初始化Acceptor就直接放到线程池去执行。        
    }
}

    下边我们分析一下Acceptor这个AbstractConnector内部类:

private class Acceptor implements Runnable
{
    private final int _id;
    private String _name;
    private Acceptor(int id)
    {
        _id = id;
    }

    @Override
    public void run()
    {    
        //刚刚我们把它放到线程池里,它会取当前执行它的线程放到AbstractConnector中的_acceptors线程数组中
        //主要是来判断acceptor是否都停掉 _stopping=new CountDownLatch(_acceptors.length)。
        //
        final Thread thread = Thread.currentThread();
        String name=thread.getName();
        _name=String.format("%s-acceptor-%d@%x-%s",name,_id,hashCode(),AbstractConnector.this.toString());
        thread.setName(_name);
        
        int priority=thread.getPriority();
        if (_acceptorPriorityDelta!=0)
            thread.setPriority(Math.max(Thread.MIN_PRIORITY,Math.min(Thread.MAX_PRIORITY,priority+_acceptorPriorityDelta)));

        synchronized (AbstractConnector.this)
        {    
            _acceptors[_id] = thread;
        }

        try
        {
            while (isAccepting())
            {
                try
                {    
                    //!!!这是个抽象方法由具体的实现类ServerConnector来实现。!!!
                    accept(_id);
                }
                catch (Throwable e)
                {
                    if (isAccepting())
                        LOG.warn(e);
                    else
                        LOG.ignore(e);
                }
            }
        }
        finally
        {
            thread.setName(name);
            if (_acceptorPriorityDelta!=0)
                thread.setPriority(priority);

            synchronized (AbstractConnector.this)
            {
                _acceptors[_id] = null;
            }
            CountDownLatch stopping=_stopping;
            if (stopping!=null)
                stopping.countDown();
        }
    }
    
    @Override
    public String toString()
    {
        String name=_name;
        if (name==null)
            return String.format("acceptor-%d@%x", _id, hashCode());
        return name;
    }
    
}

 下边我们具体介绍accept方法在ServerConnector中的具体实现,ServerConnector有两个重要的方法 open和accept

下边是具体的代码:

//主要是初始化ServerSocketChannel,绑定监听端口。剩下的接收请求交给accept方法来做。
public void open() throws IOException
{
    if (_acceptChannel == null)
    {
        ServerSocketChannel serverChannel = null;
        if (isInheritChannel())
        {
            Channel channel = System.inheritedChannel();
            if (channel instanceof ServerSocketChannel)
                serverChannel = (ServerSocketChannel)channel;
        }

        if (serverChannel == null)
        {
            serverChannel = ServerSocketChannel.open();

            InetSocketAddress bindAddress = getHost() == null ? new InetSocketAddress(getPort()) : new InetSocketAddress(getHost(), getPort());
            serverChannel.socket().setReuseAddress(getReuseAddress());
            serverChannel.socket().bind(bindAddress, getAcceptQueueSize());

            _localPort = serverChannel.socket().getLocalPort();
            if (_localPort <= 0)
                throw new IOException("Server channel not bound");

            addBean(serverChannel);
        }

        serverChannel.configureBlocking(true);
        addBean(serverChannel);

        _acceptChannel = serverChannel;
    }
}
//这个方法由AbstractConnector中的accepters调用,并发的处理接收请求。
@Override
public void accept(int acceptorID) throws IOException
{
    ServerSocketChannel serverChannel = _acceptChannel;
    if (serverChannel != null && serverChannel.isOpen())
    {
        SocketChannel channel = serverChannel.accept();
        accepted(channel);
    }
}

private void accepted(SocketChannel channel) throws IOException
{
    channel.configureBlocking(false);
    Socket socket = channel.socket();
    configure(socket);
    //交给SelectorManager来对请求过来的Channel处理
    _manager.accept(channel);
}

protected void configure(Socket socket)
{
    try
    {    
        //禁掉TCP延迟 negle算法
        socket.setTcpNoDelay(true);
        if (_lingerTime >= 0)
            socket.setSoLinger(true, _lingerTime / 1000);
        else
            socket.setSoLinger(false, 0);
    }
    catch (SocketException e)
    {
        LOG.ignore(e);
    }
}

       Connector就介绍到这里,主要是封装了ServerSocketChannel,在多线程环境下监听过来的请求,转发请求给SelectorManager。

转发标注来源:http://my.oschina.net/robinyao/blog/404687

    END------------------------------------------------------------------

© 著作权归作者所有

共有 人打赏支持
robin-yao
粉丝 154
博文 54
码字总数 61496
作品 0
杭州
Azkaban的Web Server源码探究系列3: Jetty Server初始化

上一节,主要讲了配置方面,接下来azkaban就开始启动server. talk is cheap, show the code! ================================================ 接下来主要是Jetty的Server的初始化,其实主...

强子哥哥
2016/04/06
279
0
dubbo源码学习笔记----container

Main函数启动 启动时会装载扩展: 做了一个Jvm的ShutdownHook,在JVM退出时做一些清理工作: Spring作为容器 Jetty容器

春哥大魔王的博客
01/14
0
0
在嵌入式jetty环境下运行struts2Annotation项目

本人采用struts2的注解,配置好后可以在tomcat下运行,但是使用嵌入式jetty运行时,总是出现无法找到action的问题。 package com.action; import org.apache.struts2.convention.annotation....

zhenghuazhi
2014/02/12
0
0
打包Admin

<build> <finalName>goodstaxiAdmin</finalName> <plugins> <!-- 拷贝资源插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactI......

ArlenXu
2016/10/13
2
0
java -jar rundeck-jetty-server-2.6.8.jar ,重启失败,怎么办

java -jar rundeck-jetty-server-2.6.8.jar Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/jetty/server/Connector at java.lang.Class.getDeclaredMethods0(Nat......

sca7
2016/09/26
89
0

没有更多内容

加载失败,请刷新页面

加载更多

docker run 创建一个新的容器并运行一个命令

docker run常用命令 docker run :创建一个新的容器并运行一个命令 语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 1.OPTIONS说明 -t:为容器重新分配一个伪输入终端,通常与 -i 同时使...

lwenhao
14分钟前
1
0
安装Win出现无法创建新的分区也找不到现有的分区解决方案

无法创建新的分区也找不到现有的分区 ### 首先在安装界面按下 Shift+F10### 在出现的CMD界面输入: diskpart 进入磁盘管理工具diskpart### 可以输入 : list disk 查看磁盘列表l...

Kxvz
16分钟前
1
0
关于 @ngrx/Store 下 obj 的扩展问题

昨天做 task 的时候,遇到了一个问题。 TypeError: can't define property "x": "obj" is not extensible 而我的代码是 public txTiles: Array<TransactionFilterTile>; constructor(priv......

IrisHuang
18分钟前
1
0
presto内存管理及调优

内存池 Presto有三种内存池,分别为GENERAL_POOL、RESERVED_POOL、SYSTEM_POOL。这三个内存池占用的内存大小是由下面算法进行分配的: builder.put(RESERVED_POOL, new MemoryPool(RESERVED...

张欢19933
19分钟前
1
0
Mysql5.7服务版安装

步骤1: 勾选同意协议 步骤2:选择Server only模式 步骤3:选择安装目录 步骤4:执行文件 步骤5:端口号与用户配置 步骤6:选择标准系统用户 Finish后,安装完成。...

lyle_luo
19分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部