美文网首页
tomcat源码分析(3) Connector 分析

tomcat源码分析(3) Connector 分析

作者: 全都是泡沫啦 | 来源:发表于2018-08-29 17:26 被阅读0次

快速创建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中设计

7.补充发一下张图片(http1.1默认是开始keepalive) 访问tomcat抓包的内容.png

注意:Wireshark中npcap可以进行抓取127.0.0.1的数据

相关文章

网友评论

      本文标题:tomcat源码分析(3) Connector 分析

      本文链接:https://www.haomeiwen.com/subject/adhkwftx.html