上文说了简单的servlet解析过程。实际上,tomcat在解析servlet的 时候是吧连接器定位为满足以下三个条件:
1、必须事先接口org.apache.catalina.Connector
2. 必须创建请求对象,该请求对象的类必须实现接口org.apache.catalina.Request。
3. 必须创建响应对象,该响应对象的类必须实现接口org.apache.catalina.Response。
tomcat的连接器有很多种类:Coyote、mode_jk、mod_jk2和mode_webapp等。
来自浏览器的请求类型是有区别的http/0.9 http/1.0 http/1.1.
http/1.1又叫做持久连接,上文中一次请求处理完毕就关闭了socket。然而,在现实的页面请求中需要加载多种资源(js、img css)。如果每次请求都开启关闭连接那将是非常耗时的事情。http/1.1能够让浏览器和服务器保持一种持久化的连接,快速的相应请求。这样,请求的形式就和之前不同,他是一块编码的形式,并使用特殊头部transfer-encoding感知发送过来的数据信息。同时,如果浏览器有较大数据请求之前发送头部信息Expect: 100-continue头部到服务器,等待服务器的相应。如果服务器响应数据能够接受大数据请求,才真正的发送数据,避免先发送大数据而遭服务器拒绝而浪费了传输数据的带宽资源。
本文重点说明连接器的演进。
连接器的演进主要包括了以下几个方面:
1、处理请求不再只是一次处理一次请求,而是生成Processor池,用于处理多个连接请求。同事Processor处理器也不再是每次请求新生成实例处理请求,而是从池子中获取到一个处理器去完成请求。同时,实现了Processor处理方法异步化,让连接器线程能够继续接受其他的请求。
2、处理器线程和连接器线程通过wait() notifyAll()的方式进行线程间通信。
3、Processor处理器中,增加了标识符,KeepAlive、stopped和http11,为处理器在处理的过程中设定“路口”,及时相应请求的变化。
4、socket缓冲区大小不再是像前文一样设置为定值,而是通过获取连接器传递过来的参数设置缓冲区大小。
5、处理器的职能更加的丰富。
连接处理 parseConnection,针对不同的连接协议做不同的处理。
解析请求 parseRequest
解析头部 parseHeaders
6、去掉了静态处理器,暂时无法接受静态资源请求。
------------------------
1、连接器启动:
HttpConnector connector = new HttpConnector(); SimpleContainer container = new SimpleContainer(); connector.setContainer(container); try { //初始化连接器,打开socket连接 connector.initialize(); //开启监听,开启连接器线程、将处理器线程启动并入队列。 connector.start(); System.in.read(); } catch (Exception e) { e.printStackTrace(); }
1.1 初始化连接、打开socket连接(使用工厂模式)
public void initialize() throws LifecycleException { //初始化标志,不能重复初始化 if (initialized) throw new LifecycleException ( sm.getString("httpConnector.alreadyInitialized")); this.initialized=true; Exception eRethrow = null; // Establish a server socket on the specified port try { //打开socket连接 serverSocket = open(); } catch (IOException ioe) { log("httpConnector, io problem: ", ioe); eRethrow = ioe; } catch (KeyStoreException kse) { log("httpConnector, keystore problem: ", kse); eRethrow = kse; } catch (NoSuchAlgorithmException nsae) { log("httpConnector, keystore algorithm problem: ", nsae); eRethrow = nsae; } catch (CertificateException ce) { log("httpConnector, certificate problem: ", ce); eRethrow = ce; } catch (UnrecoverableKeyException uke) { log("httpConnector, unrecoverable key: ", uke); eRethrow = uke; } catch (KeyManagementException kme) { log("httpConnector, key management problem: ", kme); eRethrow = kme; } if ( eRethrow != null ) throw new LifecycleException(threadName + ".open", eRethrow); } private ServerSocket open() throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { // Acquire the server socket factory for this Connector //获得服务器socket工厂实例 ServerSocketFactory factory = getFactory(); // If no address is specified, open a connection on all addresses //如果没有指定地址,在所有地址上打开一个连接 if (address == null) { log(sm.getString("httpConnector.allAddresses")); try { return (factory.createSocket(port, acceptCount)); } catch (BindException be) { throw new BindException(be.getMessage() + ":" + port); } } //在指定地址上打开一个连接 try { InetAddress is = InetAddress.getByName(address); log(sm.getString("httpConnector.anAddress", address)); try { return (factory.createSocket(port, acceptCount, is)); } catch (BindException be) { throw new BindException(be.getMessage() + ":" + address + ":" + port); } } catch (Exception e) { log(sm.getString("httpConnector.noAddress", address)); try { return (factory.createSocket(port, acceptCount)); } catch (BindException be) { throw new BindException(be.getMessage() + ":" + port); } } }
1.2、开启监听,开启连接器线程、将处理器线程启动并入队列。
//为连接器绑定指定数量的处理器 public void start() throws LifecycleException { //判断该线程的connect开启状态,避免重复开启 if (started) throw new LifecycleException (sm.getString("httpConnector.alreadyStarted")); threadName = "HttpConnector[" + port + "]"; //打开监听 lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; // Start our background thread //开启一个后台连接器线程 threadStart(); //创建处理器,并调用recyle方法将其放置到栈队列中 while (curProcessors < minProcessors) { if ((maxProcessors > 0) && (curProcessors >= maxProcessors)) break; HttpProcessor processor = newProcessor(); recycle(processor); } }
2、连接器、容器之间的协作关系
2.1 容器派发socket到处理器线程
public void run() { // Loop until we receive a shutdown command //开启循环,知道我们获得了结束命令 while (!stopped) { // Accept the next incoming connection from the server socket Socket socket = null; try { //获得socket请求 socket = serverSocket.accept(); // 设置超时时间 if (connectionTimeout > 0) socket.setSoTimeout(connectionTimeout); //设置tcp nodelay属性 socket.setTcpNoDelay(tcpNoDelay); } catch (AccessControlException ace) { //抛出连接安全错误信息 log("socket accept security exception", ace); continue; } catch (IOException e) { try { // If reopening fails, exit //如果再次开启失败,退出 synchronized (threadSync) { if (started && !stopped) log("accept error: ", e); if (!stopped) { // 关闭异常连接 serverSocket.close(); // 重新开启异常连接 serverSocket = open(); } } // 异常处理,包括不限于秘钥等错误请求 } catch (Exception ioe) { log("socket reopen, io problem: ", ioe); break; } continue; } //判断处理器栈是否有可用处理器,没有按规则生成,有则获取栈中处理器 HttpProcessor processor = createProcessor(); //获取处理器为空,可能情况是请求数量过多,超过了承受的最大处理器个数 if (processor == null) { try { log(sm.getString("httpConnector.noProcessor")); socket.close(); } catch (IOException e) { ; } continue; } //派发socket到处理器 processor.assign(socket); // The processor will recycle itself when it finishes } //获取到了结束命令,通知其他线程 synchronized (threadSync) { threadSync.notifyAll(); } }
2.2处理器接收到派发socket
synchronized void assign(Socket socket) { // d等待该处理器的其它socket处理执行完毕 while (available) { try { wait(); } catch (InterruptedException e) { } } // Store the newly available Socket and notify our thread //将新获取的socket放置到处理器中,并发送线程通知 this.socket = socket; available = true; notifyAll(); if ((debug >= 1) && (socket != null)) log(" An incoming request is being assigned"); }
2.3 处理器接收到了socket请求,准备处理
public void run() { // Process requests until we receive a shutdown signal while (!stopped) { // Wait for the next socket to be assigned //等待连接器的socket请求 Socket socket = await(); if (socket == null) continue; // Process the request from this socket try { //处理socket请求 process(socket); } catch (Throwable t) { log("process.invoke", t); } // Finish up this request //处理完毕,将该processor线程归还给Stack processors 用来处理接下来的socket请求 connector.recycle(this); } // Tell threadStop() we have shut ourselves down successfully synchronized (threadSync) { //该处理器线程退出,通知其他processor threadSync.notifyAll(); } }
未完待续