这次主要解析采用apr方式处理请求.apr用C实现,通过JNI调用,主要提升对静态资源(如HTML、图片、CSS、JS等)的访问性能.在tomcat下配置apr步骤:
1.下载本地库tcnative-1.dll,放在%jdk%\bin目录下(见附件).
2.在server.xml里配置listener,这个配置server.xml默认是有的
3.在server.xml里配置apr connector
在tomcat启动的时候,会调用Connector类的Start()方法,根据以上配置,Connector的start()方法里会调用Http11AprProtocol类的start()方法,如下:
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请求进行解析