前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Jetty接受请求过程

Jetty接受请求过程

作者头像
斯武丶风晴
发布于 2019-12-19 11:07:25
发布于 2019-12-19 11:07:25
1.8K00
代码可运行
举报
文章被收录于专栏:龙首琴剑庐龙首琴剑庐
运行总次数:0
代码可运行

Jetty的请求入口

ServerConnector.javaaccepted 方法(ServerSocketChannel#accept 后的处理逻辑)。

Jetty的请求流程

一个请求的流程:

  • 1.Acceptor 监听连接请求,当有连接请求到达时就接受连接,一个连接对应一个 Channel,Acceptor 将 Channel 交给 ManagedSelector 来处理。
  • 2.ManagedSelector 把 Channel 注册到 Selector 上,并创建一个 EndPointConnection 跟这个 Channel 绑定,接着就不断地检测 I/O 事件。
  • 3.I/O 事件到了就调用 EndPoint 的方法拿到一个 Runnable,并扔给线程池执行。
  • 4.线程池中调度某个线程执行 Runnable。
  • 5.Runnable 执行时,调用回调函数,这个回调函数是 Connection 注册到 EndPoint 中的。
  • 6.回调函数内部实现,其实就是调用 EndPoint 的接口方法来读数据。
  • 7.Connection 解析读到的数据,生成请求对象并交给 Handler 组件去处理。

SelectorManager

Jetty 的 Selector 由 SelectorManager 类管理,而被管理的 Selector 叫作 ManagedSelector。 (这里SelectorManager 的具体实现类是 ServerConnector的内部类 ServerConnectorManager。) SelectorManager 内部有一个 ManagedSelector 数组,真正干活的是 ManagedSelector。 主要做两个事情:

  • 选择一个 ManagedSelector 来处理 Channel
  • 提交一个任务 Accept 给 ManagedSelector
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// SelectorManager.java
    public void accept(SelectableChannel channel, Object attachment)
    {
        // 选择一个 ManagedSelector 来处理 Channel
        final ManagedSelector selector = chooseSelector();
        // 提交一个任务 Accept 给 ManagedSelector
        selector.submit(selector.new Accept(channel, attachment));
    }

ManagedSelector

ManagedSelector 在处理这个任务Accept 主要做了两步:

  • 第一步,调用 Selector 的 register 方法把 Channel 注册到 Selector 上,拿到一个 SelectionKey。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ManagedSelector$Accept.java 内部类
@Override
public void update(Selector selector){
    try{
        // 把 Channel 注册到 Selector 上,拿到一个 SelectionKey
        key = channel.register(selector, 0, attachment);
        execute(this);  // 执行当前Runnable, 跳转 run()
    } catch (Throwable x) {
        IO.close(channel);
        _selectorManager.onAcceptFailed(channel, x);
        LOG.debug(x);
    }
} 
@Override
public void run(){
    try{
        // 创建一个 EndPoint 和 Connection,并跟这个 SelectionKey(Channel)绑在一起
        createEndPoint(channel, key);
        _selectorManager.onAccepted(channel);
    } catch (Throwable x){
        LOG.debug(x);
        failed(x);
    }
}
  • 第二步,创建一个 EndPointConnection,并跟这个 SelectionKey(Channel)绑在一起:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ManagedSelector.java
private void createEndPoint(SelectableChannel channel, SelectionKey selectionKey) throws IOException{
    //1. 创建 Endpoint
    EndPoint endPoint = _selectorManager.newEndPoint(channel, this, selectionKey);
    //2. 创建 Connection
    Connection connection = _selectorManager.newConnection(channel, endPoint, selectionKey.attachment());
    //3. 把 Endpoint、Connection 和 SelectionKey 绑在一起
    endPoint.setConnection(connection);
    selectionKey.attach(endPoint);
    endPoint.onOpen();
    endPointOpened(endPoint);
    // 将Connection 注入到 EndPoint, 跳转 Connection 的 onOpen 方法 (内部转 fillInterested)
    _selectorManager.connectionOpened(connection);
}

如上,HttpConnection (Connection 的具体实现类之一) 并不会主动向 EndPoint 读取数据,而是向在 EndPoint 中注册一堆回调方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// HttpConnection.java
public void onOpen(){
    super.onOpen();
    if (isRequestBufferEmpty())
        fillInterested();
    else
        getExecutor().execute(this);
}
public void fillInterested(){
    // 告诉 EndPoint,数据到了你就调我这些回调方法 _readCallback 吧,有点异步 I/O 的感觉,也就是说 Jetty 在应用层面模拟了异步 I/O 模型。
    getEndPoint().fillInterested(_readCallback);
}
ManagedSelector 的 EatWhatYouKill

这时候,ManagedSelector 启动时候的任务 EatWhatYouKill 的 无限循环,监测到SelectorProducerprocessSelected 方法选择 出一个 Runnable 则,会自动执行。 这个 Runnable 从上步骤来看,则是 调用EndPoint 的 onSelected 方法返回一个 Runnable,然后把这个 Runnable 直接执行或扔给线程池执行。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ManagedSelector.java
_selectorManager.execute(_strategy::produce);
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ManagedSelector$SelectorProducer.java
public Runnable produce() {
    while (true) {
        Runnable task = processSelected();
        if (task != null) {
            return task;
        }
        processUpdates();
        updateKeys();
        // 唤醒select
        if (!select()) {
            return null;
        }
    }
}

具体里面就是 调用 EndPointonSelected方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ManagedSelector$SelectorProducer.java
...
if (attachment instanceof Selectable){
    // Try to produce a task
    Runnable task = ((Selectable)attachment).onSelected();
    if (task != null)
        return task;
}

EndPoint (ChannelEndPoint)

(这里EndPoint 的具体实现类是 ChannelEndPoint

这里怎么选择出这个 Runnable 呢??

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ChannelEndPoint.java

    public Runnable onSelected() {

        ....

        boolean fillable = (readyOps & SelectionKey.OP_READ) != 0;

        boolean flushable = (readyOps & SelectionKey.OP_WRITE) != 0;

        // return task to complete the job

        Runnable task = fillable

            ? (flushable

            ? _runCompleteWriteFillable

            : _runFillable)

            : (flushable

            ? _runCompleteWrite

            : null);

            

        return task;

    }

很简单,依据 selector 监听到连接上是读就绪(channel通道中有数据可读),还算写就绪(channel通道中有数据可写)。

Connection (HttpConnection)

  • 这里如果是读,则进来 AbstractConnection$ReadCallback ,即是 HttpConnection 的 onFillable() 方法 调用 EndPoint 的接口去读数据,读完后让 HTTP 解析器HttpParser去解析字节流,HTTP 解析器会将解析后的数据,包括请求行、请求头相关信息存到 Request 对象里, 然后丢给我们的 第一个Handler。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//HttpConnection.java

public void onFillable(){

    // HTTP 解析器去解析字节流

    boolean handle = parseRequestBuffer();

    ...

    // 将解析后的数据,包括请求行、请求头相关信息存到 Request 对象, 然后丢给我们的 第一个Handler

    if (handle){

    boolean suspended = !_channel.handle();

    ...

}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//HttpChannel.java

public boolean handle(){

 ...

 dispatch(DispatcherType.REQUEST, () -> {

            for (HttpConfiguration.Customizer customizer : _configuration.getCustomizers()) {

                customizer.customize(getConnector(), _configuration, _request);

                if (_request.isHandled())

                    return;

            }

            getServer().handle(HttpChannel.this);

        });

 ....

}

比如HttpChannelOverHttp (HttpChannel的具体实现类之一)

  • 这里如果是写,则进来 AbstractConnection$ReadCallback,即是 HttpConnection 的 onFillable() 方法 Connection 调用 Handler 进行业务处理,Handler 会通过 Response 对象来操作响应流,向流里面写入数据,HttpConnection 再通过 EndPoint 把数据写到 Channel,这样一次响应就完成了。

by 斯武丶风晴 https://my.oschina.net/langxSpirit

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
jetty、servlet以及spring的衔接源码分析
对于一个请求来讲,如果只是需要一个静态页面,可以直接在服务器上根据路径访问得到,但是如果请求的数据是一个动态页面,即只有在运行时从后台数据库获取,再拼装东西返回,然后生成一个对应的html文件。在Java中为了实现这个功能,使用的就是Servlet规范。
爬蜥
2019/05/26
7510
jetty启动web项目源码分析
jetty是HTTP服务,HTTP客户端,和javax.servlet的容器。它本身被设计成嵌入式模式,应该将jetty集成到自己的应用,jetty本身可以实例化,能像任何POJO一样使用,用jetty就相当于把Http服务塞进了自己的应用
爬蜥
2024/02/04
3500
jetty启动web项目源码分析
分布式 | DBLE 网络模块源码解析(二)
在上一篇文章中,我讲了网络 IO 的基础知识,本篇文章将从源码角度具体讲解 DBLE 的网络模块:包括 DBLE 是如何处理 MySQL 包的,多路复用在 DBLE 中是如何实现的,以及请求的异步化处理相关逻辑。
爱可生开源社区
2020/12/30
2970
Arthasa应用 原
Arthasa是个好东西,用熟了确实一大助力,本文主要描述如何用Arthasa解决问题(官网https://alibaba.github.io/arthas)。
尚浩宇
2018/10/10
8680
MyCat - 源代码篇(8)
对于后端连接,我们只关心MySQL的。 从后端连接工厂开始MySQLConnectionFactory.java:
干货满满张哈希
2021/04/12
3730
MyCat - 源代码篇(8)
自家表兄弟Tomcat和Jetty
Jetty是Eclipse基金会的一个开源项目,是“HTTP服务器 + Servlet容器”,并且Jetty和Tomcat在架构设计上有不少相似的地方,实在是像一对表兄弟。
春哥大魔王
2020/03/13
1.5K0
Jetty架构设计之Connector、Handler组件
Jetty是Eclipse基金会的一个开源项目,和Tomcat一样,Jetty也是一个“HTTP服务器 + Servlet容器”,并且Jetty和Tomcat在架构设计上有不少相似的地方。但同时Jetty也有自己的特点,主要是更加小巧,更易于定制化。Jetty作为一名后起之秀,应用范围也越来越广,比如Google App Engine就采用了Jetty来作为Web容器。
JavaEdge
2021/10/18
9770
Jetty基本介绍 及 与tomcat对比
bin:可执行脚本文件 demo- base: etc:Jetty模块定义的XML配置文件的目录 lib:Jetty依赖的库文件 logs:Jetty的日志目录 modules:Jetty的模块 resources:外部资源配置文件的目录 webapps:项目WAR文件的目录还需要关心根目录下的一个文件:start.d(Wondows系统是start.ini文件),它定义了Jetty的活动模块。
高广超
2018/12/12
1K0
Tars-Java网络编程源码分析
本文从Java NIO网络编程的基础知识讲到了Tars框架使用NIO进行网络编程的源码分析。
2020labs小助手
2023/03/20
3940
Netty-优化与源码
提供两个实现,我这里直接将实现加入了枚举类 Serializer.Algorithm 中
sgr997
2022/11/10
5070
Netty-优化与源码
Jetty启动过程
Connector 的实现类 ServerConnector 中,有一个_acceptors的数组,在 Connector 启动的时候, 会根据_acceptors数组的长度创建对应数量的 Acceptor,而 Acceptor 的个数可以配置。
斯武丶风晴
2019/12/20
1.5K0
Jetty 与 Tomcat
Tomcat 的关键指标有吞吐量、响应时间、错误数、线程池、CPU 以及 JVM 内存 线程池中的线程数量不足会影响吞吐量和响应时间; 但是线程数太多会耗费大量 CPU; 当内存不足时会触发频繁地 GC,耗费 CPU;
全栈程序员站长
2022/11/17
1.3K0
Jetty 与 Tomcat
一些流行Java MVC框架的调用栈
今天在ActFramework群里面谈及了Spring的调用栈, 大家都觉得调用栈太长了影响性能,也不利于调试. 我这边刚好有一个Web框架性能测试项目的代码, 其中有一些常见的Java MVC框架,包括Springboot, JFinal, NinjaFramework等, 我在代码中添加了 new RuntimeException().printStackTrace(); 用来打印调用到应用逻辑(控制器)的调用栈.下面是我的测试结果: ActFramework java.lang.RuntimeExce
老码农
2018/06/27
1.1K0
netty Reactor模式(源码死磕
1. 为什么是Reactor模式 2. Reactor模式简介 3. 多线程IO的致命缺陷 4. 单线程Reactor模型 4.1. 什么是单线程Reactor呢? 4.2. 单线程Reactor的参考代码 4.3. 单线程模式的缺点: 5. 多线程的Reactor 5.1. 基于线程池的改进 5.2. 改进后的完整示意图 5.3. 多线程Reactor的参考代码 6. Reactor持续改进 7. Reactor编程的优点和缺点 7.1. 优点 7.2. 缺点
py3study
2020/01/15
2.7K0
【Tomcat源码分析】从零开始理解 HTTP 请求处理 (第二篇)
深入探究 Connector 启动逻辑后,我们接下来需细致分析 HTTP 请求的执行流程。从客户端发出的请求,要经历哪些环节才能最终被处理?
@派大星
2024/09/20
1470
【Tomcat源码分析】从零开始理解 HTTP 请求处理 (第二篇)
java架构之路-(netty专题)初步认识BIO、NIO、AIO
  本次我们主要来说一下我们的IO阻塞模型,只是不多,但是一定要理解,对于后面理解netty很重要的
小菜的不能再菜
2020/02/21
4540
终结全网!手写Netty面试题答案
创建一个线程,注册到 Selector,将 serversocketchannel 注册到Selector selectionKey 里就有具体的事件
JavaEdge
2021/10/18
2240
Netty 源码解析 Part 0——第1篇:BIO vs NIO
https://gitee.com/wangjianxin199003/netty-source-code-analysis.git
玄姐谈AGI
2021/04/29
4210
Netty 源码解析 Part 0——第1篇:BIO vs NIO
使用Spring @Cacheable注解
出现这种异常,需要向自定义ObjectMapper,设置一些参数,而不是直接使用Jackson2JsonRedisSerializer类中黙认的ObjectMapper,看源代码可以知道,Jackson2JsonRedisSerializer中的ObjectMapper是直接使用new ObjectMapper()创建的,这样ObjectMapper会将Redis中的字符串反序列化为java.util.LinkedHashMap类型,导致后续Spring对其进行转换成报错。其实我们只要它返回Object类型就可以了。
Qwe7
2022/03/18
1.2K0
Reactor模式
Reactor模式是一种设计模式,它是基于事件驱动的,可以并发的处理多个服务请求,当请求抵达后,依据多路复用策略,同步的派发这些请求至相关的请求处理程序。
CodingDiray
2019/09/25
2K0
Reactor模式
相关推荐
jetty、servlet以及spring的衔接源码分析
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文