ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Jetty架构设计之Connector、Handler组件

2022-01-09 13:03:15  阅读:174  来源: 互联网

标签:架构设计 EndPoint 请求 ManagedSelector Server Connector Handler channel


Acceptor通过阻塞方式接受连接。

public void accept(int acceptorID) throws IOException

{

ServerSocketChannel serverChannel = _acceptChannel;

if (serverChannel != null && serverChannel.isOpen())

{

// 这里是阻塞的

SocketChannel channel = serverChannel.accept();

// 执行到这里时说明有请求进来了

accepted(channel);

}

}

接受连接成功后会调用accepted,将SocketChannel设置为非阻塞模式,然后交给Selector去处理。

private void accepted(SocketChannel channel) throws IOException

{

channel.configureBlocking(false);

Socket socket = channel.socket();

configure(socket);

// _manager是SelectorManager实例,里面管理了所有的Selector实例

_manager.accept(channel);

}

SelectorManager


Jetty的Selector由SelectorManager类管理,而被管理的Selector叫作ManagedSelector。SelectorManager内部有一个ManagedSelector,真正的打工人。

每个ManagedSelector都有自己的Selector,多个Selector可以并行管理大量的channel,提高并发,连接请求到达时采用Round Robin的方式选择ManagedSelector。

public void accept(SelectableChannel channel, Object attachment)

{

//选择一个ManagedSelector来处理Channel

final ManagedSelector selector = chooseSelector();

//提交一个任务Accept给ManagedSelector

selector.submit(selector.new Accept(channel, attachment));

}

SelectorManager从本身的Selector数组中选择一个Selector来处理这个Channel,并创建一个任务Accept交给ManagedSelector,ManagedSelector在处理这个任务主要做了两步:

  1. 调用Selector#register把Channel注册到Selector上,拿到一个SelectionKey

_key = _channel.register(selector, SelectionKey.OP_ACCEPT, this);

  1. ,创建一个EndPoint和Connection,并跟这个SelectionKey(Channel)绑定

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);

}

就好像到餐厅吃饭:

  • 先点菜(注册I/O事件)

  • 服务员(ManagedSelector)给你一个单子(SelectionKey)

  • 等菜做好了(I/O事件到了)

  • 服务员根据单子就知道是哪桌点了这个菜,于是喊一嗓子某某桌的菜做好了(调用了绑定在SelectionKey上的EndPoint的方法)

ManagedSelector并没有调用直接EndPoint的方法去处理数据,而是通过调用EndPoint的方法返回一个Runnable,然后把这个Runnable扔给线程池执行,这个Runnable才会去真正读数据和处理请求。

Connection


这个Runnable是EndPoint的一个内部类,它会调用Connection的回调方法来处理请求。Jetty的Connection组件类比就是Tomcat的Processor,负责具体协议的解析,得到Request对象,并调用Handler容器进行处理。下面我简单介绍一下它的具体实现类HttpConnection对请求和响应的处理过程。

请求处理:HttpConnection并不会主动向EndPoint读取数据,而是向在EndPoint中注册一堆回调方法:

getEndPoint().fillInterested(_readCallback);

告诉EndPoint,数据到了你就调我这些回调方法_readCallback吧,有点异步I/O的感觉,也就是说Jetty在应用层面模拟了异步I/O模型。

回调方法_readCallback里,会调用EndPoint的接口去读数据,读完后让HTTP解析器去解析字节流,HTTP解析器会将解析后的数据,包括请求行、请求头相关信息存到Request对象。

响应处理:Connection调用Handler进行业务处理,Handler会通过Response对象来操作响应流,向流里面写入数据,HttpConnection再通过EndPoint把数据写到Channel,这样一次响应就完成了。

  • Connector的工作流

1.Acceptor监听连接请求,当有连接请求到达时就接受连接,一个连接对应一个Channel,Acceptor将Channel交给ManagedSelector来处理

2.ManagedSelector把Channel注册到Selector上,并创建一个EndPoint和Connection跟这个Channel绑定,接着就不断地检测I/O事件

3.I/O事件到了就调用EndPoint的方法拿到一个Runnable,并扔给线程池执行

4.线程池中调度某个线程执行Runnable

5.Runnable执行时,调用回调函数,这个回调函数是Connection注册到EndPoint中的

6.回调函数内部实现,其实就是调用EndPoint的接口方法来读数据

7.Connection解析读到的数据,生成请求对象并交给Handler组件去处理

Handler

======================================================================

一个接口,有一堆实现类,Jetty的Connector组件调用这些接口来处理Servlet请求,我们先来看看这个接口定义成什么样子。

public interface Handler extends LifeCycle, Destroyable

{

// 处理请求的方法

public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)

throws IOException, ServletException;

// 每个Handler都关联一个Server组件,被Server管理

public void setServer(Server server);

public Server getServer();

// 销毁方法相关的资源

public void destroy();

}

任何一个Handler都需要关联一个Server组件,也就是说Handler需要被Server组件来管理。一般来说Handler会加载一些资源到内存,因此通过设置destroy方法来销毁。

Handler继承关系


Handler只是一个接口,完成具体功能的还是它的子类。那么Handler有哪些子类呢?它们的继承关系又是怎样的?这些子类是如何实现Servlet容器功能的呢?

Jetty中定义了一些默认Handler类,并且这些Handler类之间的继承关系比较复杂,我们先通过一个全景图来了解一下

Handler接口之下有抽象类AbstractHandler,之下有AbstractHandlerContainer,为什么需要这个类呢?

过渡,为实现链式调用,一个Handler内部必然要有其他Handler的引用,所以这个类的名字里才有Container。

  • HandlerWrapper和HandlerCollection都是Handler,但这些Handler里还包括其他Handler的引用

  • HandlerWrapper只包含一个其他Handler的引用,而HandlerCollection中有一个Handler数组的引用。

HandlerWrapper有两个子类:

  • Server

Handler模块的入口,必然要将请求传递给其他Handler来处理,为了触发其他Handler的调用,所以它是一个HandlerWrapper。

  • ScopedHandler

实现了“具有上下文信息”的责任链调用。Servlet规范规定Servlet在执行过程中有上下文。这些Handler在执行过程中就是通过ScopedHandler来实现的获得上下文。

ScopedHandler有一堆的子类用来实现Servlet规范,比如ServletHandler、ContextHandler、SessionHandler、ServletContextHandler和WebAppContext

HandlerCollection

维护了一个Handler数组。因为Jetty可能需要同时支持多个Web应用,如果每个Web应用有一个Handler入口,那么多个Web应用的Handler就成了一个数组,比如Server中就有一个HandlerCollection,Server会根据用户请求的URL从数组中选取相应的Handler来处理,就是选择特定的Web应用来处理请求。

Handler的类型


协调Handler

负责将请求路由到一组Handler中去,比如HandlerCollection,它内部持有一个Handler数组,当请求到来时,它负责将请求转发到数组中的某一个Handler。

过滤器Handler

自己会处理请求,处理完了后再把请求转发到下一个Handler,比如HandlerWrapper,它内部持有下一个Handler的引用。

所有继承了HandlerWrapper的Handler都具有了过滤器Handler的特征,比如ContextHandler、SessionHandler和WebAppContext等。

内容Handler

这些Handler会真正调用Servlet来处理请求,生成响应内容,比如ServletHandler。

如果浏览器请求的是一个静态资源,也有相应的ResourceHandler来处理这个请求,返回静态页面。

实现Servlet规范


上文提到,ServletHandler、ContextHandler以及WebAppContext等,它们实现了Servlet规范,那具体是怎么实现的呢?为了帮助你理解,在这之前,我们还是来看看如何使用Jetty来启动一个Web应用。

//新建一个WebAppContext,WebAppContext是一个Handler

WebAppContext webapp = new WebAppContext();

webapp.setContextPath("/mywebapp");

webapp.setWar(“mywebapp.war”);

//将Handler添加到Server中去

server.setHandler(webapp);

//启动Server

server.start();

server.join();

上面的过程主要分为两步:

第一步创建一个WebAppContext,接着设置一些参数到这个Handler中,就是告诉WebAppContext你的WAR包放在哪,Web应用的访问路径是什么。

第二步就是把新创建的WebAppContext添加到Server中,然后启动Server。

标签:架构设计,EndPoint,请求,ManagedSelector,Server,Connector,Handler,channel
来源: https://blog.csdn.net/m0_66264588/article/details/122392425

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有