Tomcat處理http請求之源碼分析
1 請求包裝處理
tomcat組件Connector在啟動的時候會監(jiān)聽端口。以JIoEndpoint為例,在其Acceptor類中:
protected class Acceptor extends AbstractEndpoint.Acceptor {
@Override
public void run() {
while (running) {
……
try {
//當前連接數(shù)
countUpOrAwaitConnection();
Socket socket = null;
try {
//取出隊列中的連接請求
socket = serverSocketFactory.acceptSocket(serverSocket);
} catch (IOException ioe) {
countDownConnection();
}
if (running && !paused && setSocketOptions(socket)) {
//處理請求
if (!processSocket(socket)) {
countDownConnection();
closeSocket(socket);
}
} else {
countDownConnection();
// Close socket right away
closeSocket(socket);
}
}
……
}
}
}在上面的代碼中,socket = serverSocketFactory.acceptSocket(serverSocket);與客戶端建立連接,將連接的socket交給processSocket(socket)來處理。在processSocket中,對socket進行包裝一下交給線程池來處理:
protected boolean processSocket(Socket socket) {
try {
SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket);
wrapper.setKeepAliveLeft(getMaxKeepAliveRequests());
wrapper.setSecure(isSSLEnabled());
//交給線程池處理連接
getExecutor().execute(new SocketProcessor(wrapper));
}
……
return true;
}線程池處理的任務SocketProccessor,通過代碼分析:
protected class SocketProcessor implements Runnable {
protected SocketWrapper<Socket> socket = null;
protected SocketStatus status = null;
@Override
public void run() {
boolean launch = false;
synchronized (socket) {
SocketState state = SocketState.OPEN;
try {
serverSocketFactory.handshake(socket.getSocket());
}
……
if ((state != SocketState.CLOSED)) {
//委派給Handler來處理
if (status == null) {
state = handler.process(socket, SocketStatus.OPEN_READ);
} else {
state = handler.process(socket,status);
}
}}}
……
}即在SocketProcessor中,將Socket交給handler處理,這個handler就是在Http11Protocol的構(gòu)造方法中賦值的Http11ConnectionHandler,在該類的父類process方法中通過請求的狀態(tài),來創(chuàng)建Http11Processor處理器進行相應的處理,切到Http11Proccessor的父類AbstractHttp11Proccessor中。
public SocketState process(SocketWrapper socketWrapper) {
RequestInfo rp = request.getRequestProcessor();
rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
// Setting up the I/O
setSocketWrapper(socketWrapper);
getInputBuffer().init(socketWrapper, endpoint);
getOutputBuffer().init(socketWrapper, endpoint);
while (!getErrorState().isError() && keepAlive && !comet && !isAsync() &&
upgradeInbound == null &&
httpUpgradeHandler == null && !endpoint.isPaused()) {
……
if (!getErrorState().isError()) {
// Setting up filters, and parse some request headers
rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
try {
//請求預處理
prepareRequest();
}
……
}
……
if (!getErrorState().isError()) {
try {
rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
//交由適配器處理
adapter.service(request, response);
if(keepAlive && !getErrorState().isError() && (
response.getErrorException() != null ||
(!isAsync() &&
statusDropsConnection(response.getStatus())))) {
setErrorState(ErrorState.CLOSE_CLEAN, null);
}
setCometTimeouts(socketWrapper);
}
}
}
……
} 可以看到Request和Response的生成,從Socket中獲取請求數(shù)據(jù),keep-alive處理,數(shù)據(jù)包裝等等信息,最后交給了CoyoteAdapter的service方法
2 請求傳遞給Container
在CoyoteAdapter的service方法中,主要有2個任務:
•第一個是org.apache.coyote.Request和
org.apache.coyote.Response到繼承自HttpServletRequest的org.apache.catalina.connector.Request和org.apache.catalina.connector.Response轉(zhuǎn)換,和Context,Wrapper定位。
•第二個是將請求交給StandardEngineValve處理。
public void service(org.apache.coyote.Request req,
org.apache.coyote.Response res) {
……
postParseSuccess = postParseRequest(req, request, res, response);
……
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
……
}在postParseRequest方法中代碼片段:
connector.getMapper().map(serverName, decodedURI, version,
request.getMappingData());
request.setContext((Context) request.getMappingData().context);
request.setWrapper((Wrapper) request.getMappingData().wrapper);request通過URI的信息找到屬于自己的Context和Wrapper。而這個Mapper保存了所有的容器信息,不記得的同學可以回到Connector的startInternal方法中,最有一行代碼是mapperListener.start(); 在MapperListener的start()方法中,
public void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
findDefaultHost();
Engine engine = (Engine) connector.getService().getContainer();
addListeners(engine);
Container[] conHosts = engine.findChildren();
for (Container conHost : conHosts) {
Host host = (Host) conHost;
if (!LifecycleState.NEW.equals(host.getState())) {
registerHost(host);
}
}
}MapperListener.startInternal()方法將所有Container容器信息保存到了mapper中。那么,現(xiàn)在初始化把所有容器都添加進去了,如果容器變化了將會怎么樣?這就是上面所說的監(jiān)聽器的作用,容器變化了,MapperListener作為監(jiān)聽者。他的生成圖示

通過Mapper找到了該請求對應的Context和Wrapper后,CoyoteAdapter將包裝好的請求交給Container處理。
3 Container處理請求流程
從下面的代碼片段,我們很容易追蹤整個Container的調(diào)用鏈: 用時序圖畫出來則是:

最終StandardWrapperValve將請求交給Servlet處理完成。至此一次http請求處理完畢。
到此這篇關(guān)于Tomcat處理http請求之源碼分析的文章就介紹到這了,更多相關(guān)Tomcat請求處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
HBuilderX配置tomcat外部服務器查看編輯jsp界面的方法詳解
這篇文章主要介紹了HBuilderX配置tomcat外部服務器查看編輯jsp界面的方法,本文通過實例圖文相結(jié)合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
tomcat 安全規(guī)范(tomcat安全加固和規(guī)范)
tomcat是一個開源Web服務器,基于Tomcat的Web運行效率高,可以在一般的硬件平臺上流暢運行,因此,頗受Web站長的青睞。不過,在默認配置下其存在一定的安全隱患,可被惡意攻擊2019-11-11
深入了解tomcat中servlet的創(chuàng)建方式實現(xiàn)
這篇文章主要介紹了深入了解tomcat中servlet的創(chuàng)建方式實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10

