快速创建Connector测试类
1.创建类名为TestConnector,执行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的桥梁,通过他将request response 传入到webapps 的应用当中
* protocolHandler.setAdapter(adapter);
* Adapter是对读写io的数据与业务处理的适配
*/
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/ 页面返回Hello World...
3.Connector的构造函数中使用setProtocol进行协议的选择创建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;
}
//省略非关键代码....
}
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();//开始接受tcp请求连接
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
}
...
}
6.通过上述步骤中我们发现connector 中大部分操作都是基于protocolHandler (默认不启动apr我们使用的是org.apache.coyote.http11.Http11NioProtocol)。我们脑子里会出现大体的流程 protocolHandler 创建服务器套接字并将其绑定到指定的本地8080端口,侦听并接受到此套接字的连接,将读取的数据封装为request 创建response,传入到Adapter 进行业务处理(写入响应码:200 写入body:Hello World...)将response中通过socket返回客户端。这个只是可以简单的描述流程,这个过程中涉及到nio的实现,线程模型的设计,长短连接的控制,如何通过优化提高并发,会在后续分析Http11NioProtocol中设计
注意:Wireshark中npcap可以进行抓取127.0.0.1的数据
网友评论