上节,只是讲了一个简单的connector实现。
本章我们来看看tomcat1.4中默认Connector真正的实现(虽然现在已经不再使用,但对我们学习原理还是有很大帮助的)。我们来看一下tomcat的一个基本的connector需要做什么:
- 实现org.apache.catalina.Connector接口
- 创建实现了org.apache.catalina.Request接口的request对象
- 创建实现了org.apache.catalina.Response接口的response对象
再看下它都做了哪些优化:
- 为一些大对象创建pool,减少了创建大对象的时间开销,典型的以空间换时间方法
- 很多地方使用char[]替代String
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啦。