幾個重要的概念
- Connector: jetty網絡接口的封裝,用於監聽網絡連接
- SelectorManager:底層selector封裝,管理網絡事件,主要是向底層selector註冊感興趣的網絡事件,並從selector中輪詢出準備好的事件
- EndPoint:socket的封裝,用於底層網絡的讀寫,一旦網絡讀寫準備好,會調用相應的connection的handle方法
- Connection:請求的抽象,比如解析請求的http協議,並調用servlet 容器,依賴EndPoint
見圖
幾個重要的線程
1) Acceptor線程
- task:org.eclipse.jetty.server.AbstractConnector.Acceptor
- 數量設定:setAcceptors(Math.max(1,(Runtime.getRuntime().availableProcessors()+3)/4));見SelectChannelConnector構造函數
- 觸發時機:見SelectChannelConnector(AbstractConnector).doStart()
- 執行線程:QueuedThreadPool中的線程
- 執行邏輯
- 輪詢SelectChannelConnector.accept(int acceptorID)
- 以阻塞的方式獲取連接請求
- 一旦獲得連接,調用ConnectorSelectorManager.register(SocketChannel channel)
- 向SelectorManager$SelectSet 內部的_changes隊列中添加該事件(有新的連接)
- 喚醒selector
2)Selector 線程
- task:匿名內部類(new Runnable(){......})
- 數量設定:在jetty.xml中配置
- 觸發時機:見SelectChannelConnector$ConnectorSelectorManager(SelectorManager).doStart()
- 執行線程:QueuedThreadPool中的線程
- 執行邏輯
- 輪詢SelectorManager$SelectSet.doSelect()
- 從_changes隊列獲取感興趣的事件
- 如果是EndPoint類型(讀寫事件)
- 如果已在selector中註冊過,則更新selection key, 否則向selector註冊
- 如果是ChannelAndAttachment類型
- 如果關聯的SocketChannel已連接,則向selector註冊讀事件
- 否則註冊連接事件
- 如果是SocketChannel類型(連接事件)
- 則向selector註冊讀事件//key = channel.register(selector,SelectionKey.OP_READ,null);
- 實例化SelectChannelEndPoint //createEndPoint(channel,key);
- 調用SelectChannelEndPoint.schedule()
- 調用SelectChannelConnector$ConnectorSelectorManager.dispatch(Runnable task)將請求扔給QueuedThreadPool(存放在內部jobs隊列)
- 如果是ChangeTask類型
- 直接執行
- 如果是Runnable
- 直接丟給QueuedThreadPool
- 如果是EndPoint類型(讀寫事件)
- 運行selector.select獲取準備好的SelectionKey,遍歷SelectionKey
- 如果key無效則去更新
- 如果有事件發生則調用SelectChannelEndPoint.schedule()
- 調用selector.selectedKeys().clear()
3)Worker線程
- task:匿名內部類(new Runnable(){......})
- 數量設定:在jetty.xml中配置
- 觸發時機:QueuedThreadPool.startThread
- 執行線程:QueuedThreadPool中的線程
- 執行邏輯:
- 輪詢從jobs隊列取job(通常是SelectChannelEndPoint的匿名內部類(new Runnable(){......}))
- 然後執行job.run(通常是SelectChannelEndPoint.handle())
- 調用SelectChannelConnector$SelectChannelHttpConnection(AsyncHttpConnection).handle()
- HttpParser.parseAvailable()(不斷調用parseNext讀取請求的內容)處理請求
- flush內容
- 如果過程中存在寫阻塞,會調用SelectChannelEndPoint.scheduleWrite()或者直接調用updateKey()往_changes隊列中添加寫事件
- 調用SelectChannelConnector$SelectChannelHttpConnection(AsyncHttpConnection).handle()
線程關係見圖
小結(請求處理流程)
- Acceptor線程負責監聽連接,一但有連接過來,寫入changes隊列
- Selector輪詢changes隊列,將隊列中的感興趣事件往selector中註冊,並從selector中查出準備好的網絡事件,一旦有準備好的網絡事件,通過調用endpoint.schedule()將task丟入線程池的jobs隊列
- Work線程會從jobs隊列取出任務,然後執行
- 上面的3組線程全來自QueuedThreadPool中的線程