快速創(chuàng)建Connector測(cè)試類
1.創(chuàng)建類名為TestConnector,執(zhí)行main方法
public class TestConnector {
public static void main(String[] args) throws Exception {
Connector connector = new Connector("HTTP/1.1");
connector.setPort(8080);
connector.init();//protocolHandler.init(); 這里主要是綁定8080端口的ServerSocketChannel
/**
* 替換init的Adapter初始化
* adapter = new CoyoteAdapter(this); //連接Service的橋梁沫勿,通過(guò)他將request response 傳入到webapps 的應(yīng)用當(dāng)中
* protocolHandler.setAdapter(adapter);
* Adapter是對(duì)讀寫(xiě)io的數(shù)據(jù)與業(yè)務(wù)處理的適配
*/
connector.getProtocolHandler().setAdapter(new Adapter() {
@Override
public void service(Request req, Response res) throws Exception {
res.setStatus(200);
res.doWrite(ByteBuffer.wrap("Hello World...".getBytes()));
}
@Override
public boolean prepare(Request req, Response res) throws Exception {
return false;
}
@Override
public boolean asyncDispatch(Request req, Response res, SocketEvent status) throws Exception {
return false;
}
@Override
public void log(Request req, Response res, long time) {
}
@Override
public void checkRecycled(Request req, Response res) {
}
@Override
public String getDomain() {
return null;
}
});
connector.start();
System.in.read();
}
}
2.瀏覽器輸入http://127.0.0.1:8080/ 頁(yè)面返回Hello World...
3.Connector的構(gòu)造函數(shù)中使用setProtocol進(jìn)行協(xié)議的選擇創(chuàng)建ProtocolHandler
public Connector(String protocol) {
setProtocol(protocol);
// Instantiate protocol handler
ProtocolHandler p = null;
try {
Class<?> clazz = Class.forName(protocolHandlerClassName);
p = (ProtocolHandler) clazz.getConstructor().newInstance();
} catch (Exception e) {
log.error(sm.getString(
"coyoteConnector.protocolHandlerInstantiationFailed"), e);
} finally {
this.protocolHandler = p;
}
//省略非關(guān)鍵代碼....
}
public void setProtocol(String protocol) {
boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
AprLifecycleListener.getUseAprConnector();
if ("HTTP/1.1".equals(protocol) || protocol == null) {
if (aprConnector) {
setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
} else {
setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
}
} else if ("AJP/1.3".equals(protocol)) {
if (aprConnector) {
setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
} else {
setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
}
} else {
setProtocolHandlerClassName(protocol);
}
}
4.connector.init();
@Override
protected void initInternal() throws LifecycleException {
...
adapter = new CoyoteAdapter(this);
protocolHandler.setAdapter(adapter);
...
try {
protocolHandler.init();//bind() serverSock.socket().bind(addr,getAcceptCount());
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
}
...
}
5.connector.start();
@Override
protected void startInternal() throws LifecycleException {
...
try {
protocolHandler.start();//開(kāi)始接受tcp請(qǐng)求連接
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
}
...
}
6.通過(guò)上述步驟中我們發(fā)現(xiàn)connector 中大部分操作都是基于protocolHandler (默認(rèn)不啟動(dòng)apr我們使用的是org.apache.coyote.http11.Http11NioProtocol)茧吊。我們腦子里會(huì)出現(xiàn)大體的流程 protocolHandler 創(chuàng)建服務(wù)器套接字并將其綁定到指定的本地8080端口,偵聽(tīng)并接受到此套接字的連接,將讀取的數(shù)據(jù)封裝為request 創(chuàng)建response,傳入到Adapter 進(jìn)行業(yè)務(wù)處理(寫(xiě)入響應(yīng)碼:200 寫(xiě)入body:Hello World...)將response中通過(guò)socket返回客戶端。這個(gè)只是可以簡(jiǎn)單的描述流程川蒙,這個(gè)過(guò)程中涉及到nio的實(shí)現(xiàn),線程模型的設(shè)計(jì)长已,長(zhǎng)短連接的控制畜眨,如何通過(guò)優(yōu)化提高并發(fā),會(huì)在后續(xù)分析Http11NioProtocol中設(shè)計(jì)
注意:Wireshark中npcap可以進(jìn)行抓取127.0.0.1的數(shù)據(jù)