分享

Jetty 服务器架构分析(中)

 java学习278 2012-03-17

Jetty 服务器架构分析(中)

分类: Web Web Server Java Architecture 1782人阅读 评论(3) 收藏 举报

    接上一篇,说到XmlConfiguration ,XmlConfiguration 利用自己实现的 IOC 组装 Server 的全过程如下图所示:

 

 
 

这里可以看到 3 个关键的配置文件, jetty.xml  jetty-deploy.xml 、以及 contexts/xxx.xml

l  Jetty.xml 文件中定义了入口类 Server, 以及其所需要的线程池、 Connector  Handler 

l  Jetty-deploy.xml 中则定义了部署 web 应用用到部署工具,在其中指定了部署 web 应用的两种方式,类似于 tomcat, 如果采用 webappProvider ,则表示将 web 应用放在 webapp下即可生效,如果采用 ContextProvider ,则需要定义 Contexts 目录所在位置,只要在该目录下放置任何应用的 context 配置文件就可以生效。

l  Xxx.xml 这是一个用户自定义文件,表示采用 ContextProvider 时,在其中定义一个WebAppContext  handler, 它指定了我们应用所在的位置,便于加载。

 

XmlConfiguration 解析装配完毕之后,就开始启动服务, Jetty 的启动是从 Server 开始的,我们来看一下服务器真正的启动过程。

 

 
 

 

 

 

 

 

从上图中我们能大概看出服务器启动过程,先是由用户设置好需要的核心组件,然后调用 Server.start() 开始启动服务,其中会首先启动 handler 处理器,之后启动用户自定义组件,这个自定义组件需要实现 LifeCyle 接口,最后才启动 Connector 接受请求。可以想到,关闭过程恰好是反过来,首先关闭接受请求的 connector ,然后再关闭用户自定义组件,最后关闭 handler.

         我们再来详细看一下 Server 源代码的核心实现过程,当调用 start 方法时,其实是调用其祖先类 AbstractLifeCycle 中方法,该方法在这里有一个模板实现,如下:

  1. public final void start() throws Exception  
  2.    {  
  3.        synchronized (_lock)  
  4.        {  
  5.            try  
  6.            {  
  7.                if (_state == __STARTED || _state == __STARTING)  
  8.                    return;  
  9.                setStarting();  
  10.                doStart();  
  11.                setStarted();  
  12.            }  
  13.            catch (Exception e)  
  14.            {  
  15.                setFailed(e);  
  16.                throw e;  
  17.            }  
  18.            catch (Error e)  
  19.            {  
  20.                setFailed(e);  
  21.                throw e;  
  22.            }  
  23.        }  

 

  • Connector 启动过程

 

看下 Connector 的详细启动过程: (  NIO 为例 )

 
 

 

NIOConnector 启动过程中,先创建了多个 SelectSet 对象,每个 SelectSet 负责一个 NIO  Selector ,专门用于监听 read 事件 ( 这里利用的多线程 Reactor 模式, http://gee.cs./dl/cpjslides/nio.pdf ) ,当然这里仅仅是创建了对象,并没有启动,后面会提到。

SelectorManager 

 

 

然后再调用 open 创建了一个 blocking 的阻塞 channel ,专门用于接受用户的新连接,我们看下:

 

  1. public void open() throws IOException  
  2.    {  
  3.        synchronized(this)  
  4.        {  
  5.            if (_acceptChannel == null)  
  6.            {  
  7.                // Create a new server socket  
  8.                _acceptChannel = ServerSocketChannel.open();  
  9.                // Set to blocking mode  
  10.                _acceptChannel.configureBlocking(true);  
  11.                // Bind the server socket to the local host and port  
  12.                _acceptChannel.socket().setReuseAddress(getReuseAddress());  
  13.                InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort());  
  14.          _acceptChannel.socket().bind(addr,getAcceptQueueSize());  
  15.                _localPort=_acceptChannel.socket().getLocalPort();  
  16.                if (_localPort<=0)  
  17.                    throw new IOException("Server channel not bound");  
  18.            }  
  19.        }  

 

随后从线程池中分配了 N  ( 可以在配置文件中配置 ) 线程用于启动 SelectSet 监听 read 事件。

 

 

 

 

 

 

 

 

  1. synchronized (this)  
  2.         {  
  3.             _acceptorThread = new Thread[getAcceptors()];  
  4.             for (int i = 0; i < _acceptorThread.length; i++)  
  5.                 _threadPool.dispatch(new Acceptor(i));  
  6.             if (_threadPool.isLowOnThreads())  
  7.                 Log.warn("insufficient threads configured for {}",this);  
  8.         }  

 

 
 

最后再分配 1 个线程用于 accept 用户的新连接,新连接来之后,会将其设置为 nonblocking 模式,之后就将其 Register给某个 SelectSet 去监听 read 事件,然后又返回来继续监听新连接:

 

  1. _manager.dispatch(new Runnable()  
  2.         {  
  3.             public void run()  
  4.             {  
  5.                 final ServerSocketChannel server=_acceptChannel;  
  6.                 while (isRunning() && _acceptChannel==server && server.isOpen())  
  7.                 {  
  8.                     try  
  9.                     {  
  10.                         SocketChannel channel = server.accept();  
  11.                         channel.configureBlocking(false);  
  12.                         Socket socket = channel.socket();  
  13.                         configure(socket);  
  14.                         _manager.register(channel);  
  15.                     }  
  16.                     catch(IOException e)  
  17.                     {  
  18.                         Log.ignore(e);  
  19.                     }  
  20.                 }  
  21.             }  
  22.         });  

 

 

 

  • Handler 启动过程

 

 
 

Jetty 将所有的真正处理请求的动作都抽象成了 Handler ,因此做事情的组件都是实现了这个接口的,包括上图所示的 WebAppContext 等等,需要做什么样的工作,那么就添加什么样的 Handler ,这里 SessionHandler 不是必须的,但是默认是创建好的。 ServletHandler 主要负责处理 web 应用的 Servlet  Filter 等工作,最后将请求直接交给 Servlet  Filter 都是在这里完成。

   这里展示的 Handler 的启动过程其实是在准备 web 应用环境,例如解析 web 应用的web.xml 等等工作,做好一切准备工作。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多