Tomcat原始碼分析(2)-聯結器Connector整體架構
在上一篇博文中,主要分析了tomcat的整體架構,通過上一篇的分析可以知道,tomcat主要有兩部分組成,分別為聯結器(Connector)和容器(Container)。本文介紹聯結器(Connector)。
一、Connector的主要功能
聯結器主要用於對外交流,它負責接收外部的請求,然後把請求轉交給container進行處理。主要功能如下:
- 監聽網路請求、接受位元組流
- 根據應用層協議(HTTP or AJP)把接受到位元組流轉換成TomcatRequest
- 把TomcatReqeust轉換成ServletRequest
- 呼叫容器Servlet,得到ServletResponse
- 把ServletRespone轉換成TomcatResponse
- 把TomcatResponse轉化成位元組流,返回給瀏覽器
基於以上詳細分析可知Connector的主要功能可以抽象為三點
- 網路監聽
- 協議解析處理
- 協議遮蔽轉換(tomcatRequest到servletReqeust轉換,servletResponse到tomcatResponse的轉換)
二、Connetor內部的元件
基於上述的分析,接下來具體看tomcat connector的程式碼元件,主要有三個
- Endpoint-用於網路監聽
- Processor-用於協議解析處理
- Adapter-用於轉換,解耦connector和container
tomcat的類設計中增加了一個ProtocolHandler, 把Endpoint和Processor,Adapter封裝到了一起。先看一個整體元件圖。
三、Endpoint介紹
Endpoint是通訊節點,實現了TCP/IP協議,包含兩個核心元件:
- Acceptor,主要用於監聽socket連結請求,
- SocketProcessor,用於處理接收到的 Socket 請求,實現了runnable介面,在run方法中會呼叫processor對socket請求進行處理。
Endpoint核心介面
public abstract class AbstractEndpoint<S> { protected Acceptor[] acceptors; protected abstract SocketProcessorBase<S> createSocketProcessor( SocketWrapperBase<S> socketWrapper, SocketEvent event); protected SynchronizedStack<SocketProcessorBase<S>> processorCache; /** * External Executor based thread pool. */ private Executor executor = null; }
這裡面還有一個Executor, 這個是tomcat自己擴充套件的執行緒池。Acceptor監聽到socket請求後,建立SocketProcessor,由Executor來執行SocketProcessor。
Acceptor核心程式碼:
protected class Acceptor extends AbstractEndpoint.Acceptor { @Override public void run() { while (running) { state = AcceptorState.RUNNING; try { //Accept the next incoming connection from the server SocketChannel socket = serverSock.accept();//監聽請求 //setSocketOptions() will hand the socket off to an appropriate processor if successful setSocketOptions(socket);//把請求傳給SocketProcessor } catch (Throwable t) { } } } }
setSocketOption最終會呼叫Endpoint的process方法。
Endpoint的process核心方法程式碼如下:
public boolean processSocket(SocketWrapperBase<S> socketWrapper, SocketEvent event, boolean dispatch) { SocketProcessorBase<S> sc = processorCache.pop(); if (sc == null) { sc = createSocketProcessor(socketWrapper, event);//建立SocketProcessor } else { sc.reset(socketWrapper, event); } Executor executor = getExecutor(); executor.execute(sc);//交給執行緒池進行處理 return true; }
SocketProcessor的抽象類
public abstract class SocketProcessorBase<S> implements Runnable { protected SocketWrapperBase<S> socketWrapper; protected SocketEvent event; @Override public final void run() { synchronized (socketWrapper) { if (socketWrapper.isClosed()) { return; } doRun(); } } protected abstract void doRun(); }
SocketProcessor類
protected class SocketProcessor extends SocketProcessorBase<NioChannel> { public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) { super(socketWrapper, event); } @Override protected void doRun() { NioChannel socket = socketWrapper.getSocket(); SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector()); getHandler().process(socketWrapper, SocketEvent.CONNECT_FAIL); } }
上面類中getHandler().process的具體實現。(Handler的介面由Endpoint的內部類進行定義。
protected static class ConnectionHandler<S> implements AbstractEndpoint.Handler<S> { private final Map<S, Processor> connections = new ConcurrentHashMap<>(); @Override public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) { S socket = wrapper.getSocket(); Processor processor = connections.get(socket); return processor.process(wrapper, status); } }
至此、請求已經成功傳給可processor。
三、processor、adapter
processor是應用層協議比如HTTP的處理。他負責把請求傳給adapter。核心程式碼如下。
@Override public SocketState service(SocketWrapperBase<?> socketWrapper) throws IOException { try { getAdapter().service(request, response); } catch (Exception e) { e.printStackTrace(); } return null; }
adapter解耦了connector和container的關係,主要負責把tomcatRequest轉換為servletRequest,然後最終呼叫container,核心程式碼如下。
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request == null) { // Create objects request = connector.createRequest(); request.setCoyoteRequest(req); response = connector.createResponse(); response.setCoyoteResponse(res); } // Calling the container connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); }
至此請求到達了container,我們的servlet會對進行業務邏輯處理。