博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《How Tomcat Works》读书笔记(四)Tomcat Default Connector
阅读量:6873 次
发布时间:2019-06-26

本文共 5211 字,大约阅读时间需要 17 分钟。

  hot3.png

上节,只是讲了一个简单的connector实现。

本章我们来看看tomcat1.4中默认Connector真正的实现(虽然现在已经不再使用,但对我们学习原理还是有很大帮助的)。

我们来看一下tomcat的一个基本的connector需要做什么:

  • 实现org.apache.catalina.Connector接口
  • 创建实现了org.apache.catalina.Request接口的request对象
  • 创建实现了org.apache.catalina.Response接口的response对象

再看下它都做了哪些优化:

  • 为一些大对象创建pool,减少了创建大对象的时间开销,典型的以空间换时间方法
  • 很多地方使用char[]替代String
HttpConnector里保存了一个HttpProcessor的栈
private Stack processors = new Stack();
还包含 Processor的最大值maxProcessors,最小值minProcessors,当前值curProcessors。
protected int minProcessors = 5;private int maxProcessors = 20;private int curProcessors = 0;

在初始化过程中会新建minProcessors个HttpProcessor

while (curProcessors < minProcessors) {    if ((maxProcessors > 0) && (curProcessors >= maxProcessors))        break;    HttpProcessor processor = newProcessor(this);    recycle(processor);}
依次放入processors栈中。
public void recycle(HttpProcessor processor) {    processors.push(processor);}
当请求到达(即accept到一个socket时), Connector从栈中取出一个Processor来进行处理。
如果不够,就新建一个Processor。
如果curProcessors已经等于maxProcessors了,那么再来请求时,如果发现无可用的Processor,那么这个请求将被忽略,直接socket.close()了。

我们来看看HttpConnector的关键代码:

public class HttpConnector implements Connector, Runnable{     public void run(){        while (!stopped) {            Socket socket = null;            try {                socket = serversocket.accept();            }catch(Exception e) {                continue;            }            //从pool中拿一个HttpProcessor            HttpProcessor processor = createProcessor();            if(processor == null){                socket.close();                continue;            }            //把请求交给HttpProcessor处理            processor.assign(socket);        }    }}    

Processor也是一个线程,在诞生之初,会被启动,然后就一直等啊等啊等....

(虽然Processor很讨厌等人,但是没办法,循环刚执行第一次,还没执行完,就得等在那里了。)

private synchronized Socket await() {    // 最初available = false    while (!available) {        try {            wait();        } catch (InterruptedException e){            ;        }    }    // Notify the Connector that we have received this    Socket socket = this.socket;    available = false;    notifyAll();    return socket;}

直到Connector哪一天翻中了它的牌子。

synchronized void assign(Socket socket) {    // Connector翻牌子的时候 available还是false 所以不用进入循环去等待    while (available) {        try {            wait();        } catch (InterruptedException e) {            ;        }    }    // Store the newly available Socket and notify our thread    this.socket = socket;    available = true;    //Connector牌子都翻好了,你得给我办"事"吧,就把还在等啊等啊等...的Processor叫醒啦    notifyAll();    ...}
看看HttpProcessor被叫醒后做了什么呢:
public class HttpProcessor implements Runnable{    public void run() {        while (!stopped) {            //等啊等啊等....            Socket socket = await();            //被唤醒            if (socket == null)                continue;            try {                //处理请求,解析requestLine、Headers、Cookie,生成Request、Response                process(socket);            } catch (Throwable t) {                log("process.invoke", t);            }            //入栈            connector.recycle(this);            ...        }    }        private void process(Socket socket){        ...        //处理完之后,调用connector的invoke方法,为什么这么做一会会提到        connector.invoke(request,response);    }}

Bootstrap启动类

public final class Bootstrap {    public static void main(string[] args) {        HttpConnector connector = new HttpConnector();        //一个简单的容器,用来承载Connector        SimpleContainer container = new SimpleContainer();        connector.setContainer(container);        try {            connector.initialize();//初始化连接器            connector.start();//启动连接器            System.in.read();        } catch (Exception e) {            e.printStackTrace();        }    }}

你已经看到了,我忘了讲SimpleContainer了。

"人"如其名:简单容器,每一个容器对应一个Connector。每一个Connector持有一个SimpleContainer的引用。HttpProcessor在process方法的最后会调用Connector中的invoke方法,Connector又调用SimpleContainer的invoke方法,看看invoke方法都做了什么:

public void invoke(Request request,Response response)                                throws IoException,ServletException {    string servletName = ((Httpservletrequest)request).getRequestURI();    servletName = servletName.substring(servletName.lastIndexof("/") + 1);    URLClassLoader loader = null;    try {        URL[] urls = new URL[1];        URLStreamHandler streamHandler = null;        File classpath = new File(WEB_ROOT);        String repository = (new URL("file",null, classpath.getCanonicalpath()                                     + File.separator)).toString();         urls[0] = new URL(null, repository, streamHandler);        loader = new URLClassLoader(urls);    } catch (IOException e) {        System.out.println(e.toString() );    }    Class myClass = null;    try {        myClass = loader.loadclass(servletName);    } catch (classNotFoundException e) {        System.out.println(e.toString());    }    servlet servlet = null;    try {        servlet = (Servlet) myClass.newInstance();        servlet.service((HttpServletRequest)request,(HttpServletResponse)response);     } catch (Exception e) {        System.out.println(e.toString());    } catch (Throwable e) {        System.out.println(e.toString());    }}
看出来了吧?容器现在负责加载我们请求的servlet,并调用service方法处理请求啦。所以我们不需要上一节中的ServletProcessor啦。

转载于:https://my.oschina.net/itjava/blog/102774

你可能感兴趣的文章
Objective-C内存布局
查看>>
qsort的另类玩法,无聊写着耍耍
查看>>
每日一乐,健康多滋味~~
查看>>
[Oracle] - Connect to a PDB of Oracle12c
查看>>
VS2015 android 设计器不能可视化问题解决。
查看>>
移动数据统计平台分析
查看>>
httppp 1.4.0 发布,HTTP响应时间监控
查看>>
ASP.NET MVC加载ASCX之后,并为之赋值
查看>>
使用SDWebImage淡入淡出的方式加载图片
查看>>
nmon与nmonanalyser系统性能分析
查看>>
52. N-Queens II
查看>>
字符串匹配算法
查看>>
LAMP学习路线图
查看>>
MySQL入门(四)
查看>>
详解 ML2 Core Plugin(II) - 每天5分钟玩转 OpenStack(72)
查看>>
httpd-2.2 配置及用法完全攻略
查看>>
IntelliJ_编译一直报错“找不到符号”
查看>>
【Mongodb】3.X 配置身份验证
查看>>
云计算就像马拉松 京东CTO为啥这么说
查看>>
2017阿里UCAN大会,听听大咖们都讲了啥
查看>>