热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《HowTomcatWorks》读书笔记(四)TomcatDefaultConnector

为什么80%的码农都做不了架构师?上节《HowTomcatWorks》读书笔记(三),只是讲了一个简单的connect

为什么80%的码农都做不了架构师?>>>   hot3.png

上节《How Tomcat Works》读书笔记(三),只是讲了一个简单的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 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中拿一个HttpProcessorHttpProcessor processor = createProcessor();if(processor == null){socket.close();continue;}//把请求交给HttpProcessor处理processor.assign(socket);}}
}    

Processor也是一个线程,在诞生之初,会被启动,然后就一直等啊等啊等....
(虽然Processor很讨厌等人,但是没办法,循环刚执行第一次,还没执行完,就得等在那里了。)

private synchronized Socket await() {// 最初available = falsewhile (!available) {try {wait();} catch (InterruptedException e){;}}// Notify the Connector that we have received thisSocket 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 threadthis.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、Responseprocess(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();//一个简单的容器,用来承载ConnectorSimpleContainer 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



推荐阅读
author-avatar
mobiledu2502912043
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有