servlet解析演进(2-1)

上文说了简单的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();
    }
}

未完待续

你可能感兴趣的:(servlet解析演进(2-1))