Tomcat处理请求的类Connector<三>

这次主要解析采用apr方式处理请求.apr用C实现,通过JNI调用,主要提升对静态资源(如HTML、图片、CSS、JS等)的访问性能.在tomcat下配置apr步骤:

  1.下载本地库tcnative-1.dll,放在%jdk%\bin目录下(见附件).

  2.在server.xml里配置listener,这个配置server.xml默认是有的  

Xml代码

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

3.在server.xml里配置apr connector 

<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"   
          connectionTimeout="20000"   
          redirectPort="8443" />

在tomcat启动的时候,会调用Connector类的Start()方法,根据以上配置,Connector的start()方法里会调用Http11AprProtocol类的start()方法,如下:

Java代码

try {  
     protocolHandler.start();  
 } catch (Exception e) {  
     String errPrefix = "";  
     if(this.service != null) {  
         errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";  
     }  
  
     throw new LifecycleException  
         (errPrefix + " " + sm.getString  
          ("coyoteConnector.protocolHandlerStartFailed", e));  
 }

Http11AprProtocol类的start()方法又会调用AprEndpoint类的start()方法,如下: 

try {  
       endpoint.start();  
} catch (Exception ex) {  
       log.error(sm.getString("http11protocol.endpoint.starterror"), ex);  
       throw ex;  
}

AprEndpoint类的start()方法如下: 

public void start() throws Exception {  
        // Initialize socket if not done before  
        if (!initialized) {  
            init();  
        }  
        if (!running) {  
            running = true;  
            paused = false;  
  
            // Create worker collection  
            if (executor == null) {  
                workers = new WorkerStack(maxThreads);  
            }  
  
            // Start poller threads  
            pollers = new Poller[pollerThreadCount];  
            for (int i = 0; i < pollerThreadCount; i++) {  
                pollers[i] = new Poller(false);  
                pollers[i].init();  
                pollers[i].setName(getName() + "-Poller-" + i);  
                pollers[i].setPriority(threadPriority);  
                pollers[i].setDaemon(true);  
                pollers[i].start();  
            }  
  
            // Start comet poller threads  
            cometPollers = new Poller[pollerThreadCount];  
            for (int i = 0; i < pollerThreadCount; i++) {  
                cometPollers[i] = new Poller(true);  
                cometPollers[i].init();  
                cometPollers[i].setName(getName() + "-CometPoller-" + i);  
                cometPollers[i].setPriority(threadPriority);  
                cometPollers[i].setDaemon(true);  
                cometPollers[i].start();  
            }  
  
            // Start sendfile threads  
            if (useSendfile) {  
                sendfiles = new Sendfile[sendfileThreadCount];  
                for (int i = 0; i < sendfileThreadCount; i++) {  
                    sendfiles[i] = new Sendfile();  
                    sendfiles[i].init();  
                    sendfiles[i].setName(getName() + "-Sendfile-" + i);  
                    sendfiles[i].setPriority(threadPriority);  
                    sendfiles[i].setDaemon(true);  
                    sendfiles[i].start();  
                }  
            }  
  
            // Start acceptor threads  
            acceptors = new Acceptor[acceptorThreadCount];  
            for (int i = 0; i < acceptorThreadCount; i++) {  
                acceptors[i] = new Acceptor();  
                acceptors[i].setName(getName() + "-Acceptor-" + i);  
                acceptors[i].setPriority(threadPriority);  
                acceptors[i].setDaemon(getDaemon());  
                acceptors[i].start();  
            }  
  
        }  
 }

该方法主要初始化接受socket的线程和处理socket的线程池.Acceptor的run()方法如下: 

public void run() {  
  
            // Loop until we receive a shutdown command  
            while (running) {  
  
                // Loop if endpoint is paused  
                while (paused && running) {  
                    try {  
                        Thread.sleep(1000);  
                    } catch (InterruptedException e) {  
                        // Ignore  
                    }  
                }  
  
                if (!running) {  
                    break;  
                }  
                try {  
                    // Accept the next incoming connection from the server socket  
                    long socket = Socket.accept(serverSock);  
                    /* 
                     * In the case of a deferred accept unlockAccept needs to 
                     * send data. This data will be rubbish, so destroy the 
                     * socket and don't process it. 
                     */  
                    if (deferAccept && (paused || !running)) {  
                        destroySocket(socket);  
                        continue;  
                    }  
                    // Hand this socket off to an appropriate processor  
                    if (!processSocketWithOptions(socket)) {//把socket交给woker线程进行转发  
                        // Close socket and pool right away  
                        destroySocket(socket);  
                    }  
                } catch (Throwable t) {  
                    if (running) {  
                        String msg = sm.getString("endpoint.accept.fail");  
                        if (t instanceof Error) {  
                            Error e = (Error) t;  
                            if (e.getError() == 233) {  
                                // Not an error on HP-UX so log as a warning  
                                // so it can be filtered out on that platform  
                                // See bug 50273  
                                log.warn(msg, t);  
                            } else {  
                                log.error(msg, t);  
                            }  
                        } else {  
                                log.error(msg, t);  
                        }  
                    }  
                }  
  
            }  
  
        }  
  
    }

Socket.accept(serverSock)方法的Socket类是用JNI实现的不同于java的Socket类,所以 Socket.accept(serverSock)返回的参数是long类型的.processSocketWithOptions(socket)方法如下: 

protected boolean processSocketWithOptions(long socket) {  
    try {  
        if (executor == null) {  
            getWorkerThread().assignWithOptions(socket);  
        } else {  
            executor.execute(new SocketWithOptionsProcessor(socket));  
        }  
    } catch (Throwable t) {  
        // This means we got an OOM or similar creating a thread, or that  
        // the pool and its queue are full  
        log.error(sm.getString("endpoint.process.fail"), t);  
        return false;  
    }  
    return true;  
}

再来看一下woker线程的run方法(): 

public void run() {  
  
    // Process requests until we receive a shutdown signal  
    while (running) {  

	// Wait for the next socket to be assigned  
	long socket = await();  
	if (socket == 0)  
	    continue;  

	if (!deferAccept && options) {  
	    if (setSocketOptions(socket)) {  
		getPoller().add(socket);//将sokcet交给poller转发.poller最终会把socket交给worker处理不知道为什么这么做  
	    } else {  
		// Close socket and pool  
		destroySocket(socket);  
		socket = 0;  
	    }  
	} else {  

	    // Process the request from this socket  
	    if ((status != null) && (handler.event(socket, status) == Handler.SocketState.CLOSED)) {  
		// Close socket and pool  
		destroySocket(socket);  
		socket = 0;  
	    } else if ((status == null) && ((options && !setSocketOptions(socket))  
		    || handler.process(socket) == Handler.SocketState.CLOSED)) {//Http11AprProtocol.Http11ConnectionHandler.process(socket)处理socket  
		// Close socket and pool  
		destroySocket(socket);  
		socket = 0;  
	    }  
	}  

	// Finish up this request  
	recycleWorkerThread(this);  

    }  

}

可以看到,woker的run()方法做了两件事.1.把socket交给poller.2.直接调用处理 Http11AprProtocol.Http11ConnectionHandler.process(socket)处理socket

 handler.process(socket)方法如下:   

public SocketState process(long socket) {  
           Http11AprProcessor processor = recycledProcessors.poll();  
           try {  
               if (processor == null) {  
                   processor = createProcessor();  
               }  
  
               if (processor instanceof ActionHook) {  
                   ((ActionHook) processor).action(ActionCode.ACTION_START, null);  
               }  
  
               SocketState state = processor.process(socket);//真正的解析http请求的方法  
               if (state == SocketState.LONG) {//如果是长连接再放回线程池处理  
                   // Associate the connection with the processor. The next request   
                   // processed by this thread will use either a new or a recycled  
                   // processor.  
                   connections.put(socket, processor);  
                   proto.endpoint.getCometPoller().add(socket);  
               } else {  
                   recycledProcessors.offer(processor);  
               }  
               return state;  
  
           } catch (java.net.SocketException e) {  
               // SocketExceptions are normal  
               Http11AprProtocol.log.debug  
                   (sm.getString  
                    ("http11protocol.proto.socketexception.debug"), e);  
           } catch (java.io.IOException e) {  
               // IOExceptions are normal  
               Http11AprProtocol.log.debug  
                   (sm.getString  
                    ("http11protocol.proto.ioexception.debug"), e);  
           }  
           // Future developers: if you discover any other  
           // rare-but-nonfatal exceptions, catch them here, and log as  
           // above.  
           catch (Throwable e) {  
               // any other exception or error is odd. Here we log it  
               // with "ERROR" level, so it will show up even on  
               // less-than-verbose logs.  
               Http11AprProtocol.log.error  
                   (sm.getString("http11protocol.proto.error"), e);  
           }  
           recycledProcessors.offer(processor);  
           return SocketState.CLOSED;  
       } 

processor.process(socket)调用的是Http11AprProcessor类的process(long socket) 方法,用http协议对http请求进行解析 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值