文档章节

Jetty源码-Server-Connector

robin-yao
 robin-yao
发布于 2015/04/21 22:55
字数 982
阅读 94
收藏 0
点赞 0
评论 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
粉丝 150
博文 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
Jetty 的工作原理以及与 Tomcat 的比较

Jetty 的基本架构 Jetty 目前的是一个比较被看好的 Servlet 引擎,它的架构比较简单,也是一个可扩展性和非常灵活的应用服务器,它有一个基本数据模型,这个数据模型就是 Handler,所有可以被...

IBMdW
2011/09/21
2.7K
1
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
请问,同样的程序,在myeclipse中可以正常运行,导入intellij后,出错。

尝试过只导入src和pom.xml,但是仍然不能运行。该项目从git下载,是一个示例程序,本身没问题,Myeclipse能运行成功。求助各路大神们! 出错信息: Exception in thread "main" java.lang.N...

qiqi1900
2017/05/20
131
1
使用jetty-maven-plugin插件进行测试

为了能够使用maven的jetty插件对项目进行测试,需要进行如下操作: (1)修改maven配置文件 为了能够在命令行中使用jetty命令,需要修改maven的配置文件settings.xml文件,添加如下配置代码:...

imzdx
2016/05/18
0
0
如何设置(修改)jetty(maven插件maven-jetty-plugi)的端口

在使用jetty的maven插件,有两种方式来改变jetty server的端口,第一种方式较为简单,即: 通过命令行指定端口: 另一种方式是在pom中的配置中通过指定新的connector来实现的,例如下述的配置...

丢失的羊羔
2016/03/31
39
0
jfinal项目部署在Linux下出错

错误如下:java.lang.NoSuchMethodError: javax.servlet.ServletContext.getJspConfigDescriptor()Ljavax/servlet/descriptor/JspConfigDescriptor; 部署环境:redhat、jetty-6.1.22 项目环境......

麦海贤
2013/11/12
238
2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

大数据教程(2.13):keepalived+nginx(多主多活)高可用集群搭建教程【自动化脚本】

上一章节博主为大家介绍了目前大型互联网项目的keepalived+nginx(主备)高可用系统架构体系,相信大家应该看了博主的文章对keepalived/nginx技术已经有一定的了解,在本节博主将为大家分享k...

em_aaron
6分钟前
0
0
Git 2.18版本发布:支持Git协议v2,提升性能

在最新的官方 Git 客户端正式版2.18中添加了对 Git wire 协议 v2 的支持,并引入了一些性能与 UI 改进的新特性。在 Git 的核心团队成员 Brandon Williams 公开宣布这一消息前几周,Git 协议 ...

六库科技
11分钟前
0
0
Java8新特性之接口

在JDK8以前,我们定义接口类中,方法都是抽象的,并且不能存在静态方法。所有的方法命名规则基本上都是 public [返回类型] [方法名](参数params) throws [异常类型] {}。 JDK8为接口的定义带...

developlee的潇洒人生
49分钟前
0
0
aop + annotation 实现统一日志记录

aop + annotation 实现统一日志记录 在开发中,我们可能需要记录异常日志。由于异常比较分散,每个 service 方法都可能发生异常,如果我们都去做处理,会出现很多重复编码,也不好维护。这种...

长安一梦
今天
2
0
将博客搬至CSDN

AHUSKY
今天
1
0
Python web框架Django学习(1)

1.Django简介 (1)Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。Django是一个开放源代码的Web应用框架,由Python写成。 (2...

十年磨一剑3344
今天
0
0
Databook-数据之书

Databook-数据之书 用于数据分析的Jupyter Notebooks。 不需购买服务器,快速开始自己的数据分析过程。 源码:https://github.com/openthings/databook 作者:openthings,https://github.co...

openthings
今天
7
0
Python PIPEs

https://www.python-course.eu/pipes.php https://www.tutorialspoint.com/python/os_pipe.htm

zungyiu
今天
1
0
gRPC学习笔记

gRPC编程流程 1. proto文件定义 proto文件用于定义需要通过gRPC生成的接口,可以理解为接口定义文档 2. 通过构建工具生成服务基类代码-Maven或Gradle 3. 服务端开发 服务端实现类须实现通过构...

OSC_fly
今天
0
0
Docker Mac (三) Dockerfile 及命令

Dockerfile 最近学习docker的时候,遇到一件怪事,关于docker镜像可能会被破坏,还不知道它会有此措施 所以需要了解构建Dockerfile的正确方法 Dockerfile是由一系列命令和参数构成的脚本,这些命...

___大侠
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部