<深入剖析Tomcat>摘抄
1.primitiveServlet.java類的定義
import javax.servlet.*; import java.io.IOException; import java.io.PrintWriter;public class PrimitiveServlet implements Servlets {public void init(ServletConfig config) throws ServletException {System.out.println("init");}public void service(ServletRequest request, ServletResponse response)throws ServletException, IOException {System.out.println("from service");PrintWriter out = response.getWriter();out.println("Hello, Roses are red.");out.print("Violets are blue.");}public void destroy() {System.out.println("destroy");}public String getServletInfo() {return null;}public ServletConfig getServletConfig() {return null;} }簡單來說,對一個Servlet的每個HTTP請求,一個功能齊全的servlet容器有以下幾件事要做:
(1). 當第一次調用某個servlet時,要載入該servlet類,并調用其init()方法(僅此一次);
(2) 針對每個request請求,創建一個javax.servlet.ServletRequest實例和一個javax.servlet.ServletResponse實例:
(3) 調用該servlet的service()方法,將servletRequest對象和servletResponse對象作為參數傳入;
(4) 當關閉該servlet類時,調用其destroy()方法,并卸載該servlet類。
2.HttpServer1類的await()方法
package ex02.pyrmont;import java.net.Socket; import java.net.ServerSocket; import java.net.InetAddress; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException;public class HttpServer1 {//shutdown commandprivate static final String SHUTDOWN_COMMAND = "/SHUTDOWN";// the shutdown command receivedprivate boolean shutdown = false;public static void main(String[] args) {HttpServer1 server = new HttpServer1();server.await();}public void await() {ServerSocket serverSocket = null;int port = 8080;try {serverSocket = new ServerSocket(port, 1,InetAddress.getByName("127.0.0.1"));}catch (IOException e){e.printStackTrace();System.exit(1);}// Loop waiting for a requestwhile (!shutdown) {Socket socket = null;InputStream input = null;OutputStream output = null;try {socket = serverSocket.accept();input = socket.getInputStream();output = socket.getOutputStream();// create Request object and parseRequest request = new Request(input);request.parse();// create Response objectResponse response = new Response(output);response.setRequest(request);// check if this is a request for a servlet or// a static resource// a request for a servlet begins with "/servlet/"if (request.getUri().startsWith("/servlet/")) {ServletProcessor1 processor = new ServletProcessor1();processor.process(request, response);}else {StaticResourceProcessor processor = new StaticResourceProcessor();processor.process(request, response);}// Close the socketsocket.close();// check if the previous URI is a shutdown commandshutdown = request.getUri().equals(SHUTDOWN_COMMAND);}catch (Exception e) {e.printStackTrace();System.exit(1);}}} }3.Request類
package ex02.pyrmont;import java.io.InputStream; import java.io.IOException; import java.io.BufferedReader; import java.io.UnsupportedEncodingException; import java.util.Enumeration; import java.util.Locale; import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest;public class Request implements ServletRequest {private InputStream input;private String uri;public Request(InputStream input) {this.input = input;}public String getUri() {return uri;}private String parseUri(String requestString) {int index1, index2;index1 = requestString.indexOf(' ');if (index1 != -1) {index2 = requestString.indexOf(' ', index1 + 1);if (index2 > index1) return requestString.substring(index1 + 1, index2);}return null;}public void parse() {// Read a set of characters from the socketStringBuffer request = new StringBuffer(2048);int i;byte[] buffer = new byte[2048];try {i = input.read(buffer);}catch (IOException e) {e.printStackTrace();i = -1;}for (int j=0; j<i; j++) {request.append((char) buffer[j]);}System.out.print(request.toString());uri = parseUri(request.toString());}/* implementation of ServletRequest */public Object getAttribute(String attribute) {return null;}public Enumeration getAttributeNames() {return null;}public String getRealPath(String path) {return null;}public RequestDispatcher getRequestDispatcher(String path) {return null;}public boolean isSecure() {return false;}public String getCharacterEncoding() {return null;}public int getContentLength() {return 0;}public String getContentType() {return null;}public ServletInputStream getInputStream() throws IOException {return null;}public Locale getLocale() {return null;}public Enumeration getLocales() {return null;}public String getParameter(String name) {return null;}public Map getParameterMap() {return null;}public Enumeration getParameterNames() {return null;}public String[] getParameterValues(String parameter) {return null;}public String getProtocol() {return null;}public String getProtocol() {return null;}public BufferedReader getReader() throws IOException {return null;}public String getRemoteAddr() {return null;}public String getScheme() {return null;}public String getServerName() {return null;}public int getServerPort() {return 0;}public void removeAttribute(String attribute) { }public void setAttribute(String key, Object value) { }public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException{ }}4.Response類
package ex02.pyrmont;import java.io.OutputStream; import java.io.IOException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.File; import java.io.PrintWriter; import java.util.Locale; import javax.servlet.ServletResponse; import javax.servlet.ServletOutputStream;public class Response implements ServletResponse {private static final int BUFFER_SIZE = 1024;Request request;OutputStream output;PrintWriter writer;public Response(OutputStream output) {this.output = output;}public void setRequest (Request request) {this.request = request;}/* This method is used to serve static pages */public void sendStaticResource() throws IOException {byte[] bytes = new byte[BUFFER_SIZE];FileInputStream fis = null;try {/* request.getUri has been replaced by request.getRequestURI */File file = new File(COnstants.WEB_ROOT, request.getUri());fis = new FileInputStream(file);/*HTTP Response = Status-Line*(( general-header | response-header | entity-header ) CRLF)CRLF[ message-body ]Status-Line = HTTP-Version SP Status-Code SP Resson-Phrase CRLF*/int ch = fis.read(bytes, 0, BUFFER_SIZE);while (ch != -1) {output.write(bytes, 0, ch);ch = fis.read(bytes, 0, BUFFER_SIZE);}}catch (FileNotFoundException e) {String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +"Content-Type: text/html\r\n" +"Content-Length: 23\r\n" +"\r\n" +"<h1>File Not Found</h1>";output.write(errorMessage.getBytes());}finally {if (fis != null) fis.close();}}/** implementation of ServletResponse */public void flushBuffer() throws IOException { }public int getBufferSize() {return 0;}public String getCharacterEncoding() {return null;}public Locale getLocale() {return null;}public ServletOutputStream getOutputStream() throws IOException {return null;}public PrintWriter getWriter() throws IOException {//autoflush is true, println() will flush,// but print() will not.writer = new PrintWriter(output, true);return writer;}public boolean isCommitted() {return false;}public void reset() { }public void resetBuffer() { }public void setBufferSize(int size) { }public void setContentLength(int length) { }public void setContentType(String type) { }public void setLocale(Locale locale) { } }5.
private static Hashtable managers = new Hashtable(); public synchronized static StringManagergetManager(String packageName) {StringManager mgr = (StringManager)managers.get(packageName);if (mgr == null) {mgr = new StringMangager(packageName);managers.put(packageName, mgr);}return mgr; }SocketInputStream類提供了兩個重要的方法,分別是readRequestLine()和readHeader()。readRequestLine()方法會返回一個HTTP請求中第1行的內容,即包含了URI、請求方法和HTTP版本信息的內容。由于從套接字的輸入流中處理字節流是指讀取從第1個字節到最后1個字節(無法從后向前讀取)的內容,因此readRequestLine()方法必須在readHeader()方法之前調用。每次調用readerHeader()方法都會返回一個名/值對,所以應重復調用readHeader()方法,直到讀取了所有的請求頭信息。readRequestLine()方法的返回值是一個HttpRequestLiine實例,readHeader()方法的返回值是一個HttpHeader對象。
6.HttpProcessor類的process()方法接收來自傳入的HTTP請求的套接字。對每個傳入的HTTP請求,它要完成4個操作:
(1). 創建一個HttpRequest對象;
(2) 創建一個HttpResponse對象;
(3) 解析HTTP請求的第1行內容和請求頭信息,填充HttpRequest對象;
(4) 將HttpRequest對象和HttpResponse對象傳遞給servletProcessor或StaticResourceProcessor的process()方法。與第2章中相同,servletProcessor類會調用請求的servlet實例的service()方法,StaticResourceProcessor類會將請求的靜態資源發送給客戶端。
HttpProcessor類的process()方法
public void process(Socket socket) {SocketInputStream input = null;OutputStream output = null;try {input = new SocketInputStream(socket.getInputStream(), 2048);output = socket.getOutputStream();// create HttpRequest object and parserequest = new HttpRequest(input);// create HttpResponse objectresponse = new HttpResponse(output);response.setRequest(request);response.setHeader("Server", "Pyrmont Servlet Container");parseRequest(input, output);parseHeaders(input);//check if this is a request for a servlet or a static resource// a request for a servlet begins with "/servlet/"if (request.getRequestURI().startsWith("/servlet/")) {ServletProcessor processor = new ServletProcessor();processor.process(request, response);} else {StaticResourceProcessor processor = new StaticResourceProcessor();processor.process(request, response);}// Close the socketsocket.close();// no shutdown for this application}catch (Exception e) {e.printStackTrace();} }7.HttpProcessor類中的parseRequest()方法的實現
private void parseRequest(SocketInputStream input, OutputStream output)throws IOException, ServletException {// Parse the incoming request lineinput.readRequestLine(requestLine);String method = new String(requestLine.method, 0, requestLine.methodEnd);String url = null;String protocol = new String(requestLine.protocol, 0,requestLine.protocolEnd);// Validate the incoming request lineif (method.length() < 1) {throw new ServletException("Missing HTTP requet method");} else if (requestLine.uriEnd < 1) {throw new ServletException("Missing HTTP request URI");}// Parse any query parameters out of the request URIint question = requestLine.indexOf("?");if (question >= 0) {request.setQueryString(new String(requestLine.uri, question + 1,requestLine.uriEnd - question - 1));uri = new String(requestLine.uri, 0, question);}else {request.setQueryString(null);uri = new String(requestLine.uri, 0, requestLine.uriEnd);}// Checking for an absolute URI (with the HTTP protocol)if (!uri.startsWith("/")) {int pos = uri.indexOf("://");// Parsing out protocol and host nameif (pos != -1) {pos = uri.indexOf('/', pos + 3);if (pos == -1) {uri = "";} else {uri = uri.substring(pos);}}}// Parse any requested session ID out of the request URIString match = ";jsessionid=";int semicolon = uri.indexOf(match);if (semicolon >= 0) {String rest = uri.substring(semicolon + match.length());int semicolon2 = rest.indexOf(';');if (semicolon2 >= 0){request.setRequestedSessionId(rest.substring(0, semicolon2));rest = rest.substring(semicolon2);}else {request.setRequestedSessionId(rest);rest = "";}request.setRequestedSessionURL(true);uri = uri.substring(0, semicolon) + rest;} else {request.setRequestedSessionId(null);request.setRequestedSessionURL(false);}// Normalize URI (using String operations at the moment)String normalizedUri = normalize(uri);// Set the corresponding request properties((HttpRequest) request).setMethod(method);request.setProtocol(protocol);if (normalizedUri != null) {((HttpRequest) request).setRequestURI(normalizedUri);}else {((HttpRequest) request).setRequestedURI(uri);}if (normalizedUri == null) {throw new ServletException("Invalid URI: " + uri + "'");} }8.org.apache.catalina.util.RequestUtil類的parseCookieHeader()方法的實現
public static Cookie[] parseCookieHeader(String header) {if ((header == null) || (header.length() < 1))return (new Cookie[0]);ArrayList cookies = new ArrayList();while (header.length() > 0) {int semicolon = header.indexOf(';');if (semicolon < 0)semicolon = header.length();if (semicolon == 0)break;String token =header.substring(0, semicolon);if (semicolon < header.length())header = header.substring(semicolon + 1);elseheader = "";try {int equals = token.indexOf('=');if (equals > 0) {String name = token.substring(0, equals).trim();String value = token.substring(equals+1).trim();cookies.add(new Cookie(name, value));}}catch (Throwable e) {;}}return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()])); }9.處理請求參數
// Parse any parameters specified in the query string String queryString = getQueryString(); trye {RequestUtil.parseParameters(results, queryString, encoding); } catch (UnsupportedEncodingException e) {; }// Parse any parameters specified in the input stream String contentType = getContentType(); if (contentType == null)contentType = ""; int semicolon = contentType.indexOf(';'); if (semicolon >= 0) {contentType = contentType.substring(0, semicolon).trim(); } else {contentType = contentType.trim(); } if ("POST".equals(getMethod()) && (getContentLength() > 0)&& "application/x-www-form-urlencoded".equals(contentType)) {try {int max = getContentLength();int len = 0;byte buf[] = new byte[getContentLength()];ServletInputStream is = getInputStream();while (len < max) {int next = is.read(buf, len, max - len);if (next < 0) {break;}len += next;}is.close();if (len < max) {throw new RuntimeException("Content length mismatch");}RequestUtil.parseParameters(results, buf, encoding);}catch (UnsupportedEncodingException ue) {;}catch (IOException e) {throw new RuntimeException("Content read fail");} }此外,process()方法使用HttpRequestFacade類和HttpResponseFacade類作為request和response對象的外觀類。當調用完servlet的service()方法后,它還會調用一次HttpResponse類的finishResponse()方法:
servlet = (Servlet) myClass.newInstance(); HttpRequestFacade requestFacade = new HttpRequestFacade(request); HttpResponseFacade responseFacade = newHttpResponseFacade(response); servlet.service(requestFacade, responseFacade);((HttpResponse) response).finishResponse();10.Tomcat中的連接器是一個獨立的模塊,可以被插入到servlet容器中,而且還有很多連接器可以使用。例如Coyote、mod_jk、mod_jk2和mod_webapp等。Tomcat中使用的連接器必須滿足一下要求:
(1). 實現org.apache.catalina.Connector接口;
(2) 負責創建實現了org.apache.catalina.Request接口的request對象;
(3) 負責創建實現了org.apache.catalina.Response接口的response對象.
11.HttpProcessor類中run()方法的實現
public void run() {// Process requests until we receive a shutdown signalwhile (!stopped) {// Wait for the next socket to be assignedSocket socket = await();if (socket == null) continue;// Process the request from this sockettry {process(socket);}catch (Throwable t) {log("process.invoke", t);}// Finish up this requestconnector.recycle(this);}// Tell threadStop() we have shut ourselves down successfullysynchronized (threadSync) {threadSync.notifyAll();} }12.下面的代碼是HttpProcessor類的assign()方法和await()方法的實現:
synchronized void assign(Socket socket) {// Wait for the Processor to get the previous Socketwhile (available) {try {wait();}catch (InterruptedException e) {}}// Store the newly available Socket and notify our threadthis.socket = socket;available = true;notifyAll();... }private synchronized Socket await() {// Wait for the Connector to provide a new Socketwhile (!available) {try {wait();}catch (InterruptedException e) {}}//Notify the Connector that we have received this SocketSocket socket = this.socket;available = false;notifyAll();if ((debug >= 1) && (socket != null))log(" The incoming request has been awaited");return (socket); }13.parseConnection()方法的實現
private void parseConnection(Socket socket) throws IOException, ServletException {if (debug >= 2)log(" parseConnection: address=" + socket.getInetAddress() +", port=" + connector.getPort());((HttpRequestImpl) request).setInet(socket.getInetAddress());if (proxyPort != 0)requset.setServerPort(proxyPort);elserequest.setServerPort(serverPort);request.setSocket(socket); }14.Bootstrap類的實現代碼
package ex04.pyrmont.startup; import ex04.pyrmont.core.SimpleContainer; import org.apache.catalina.connector.http.HttpConnector;public final class Bootstrap {public static void main(String[] args) {HttpConnector connector = new HttpConnector();SimpleContainer container = new SimpleContainer();connector.setContainer(container);try {connector.initialize();connector.start();// make the application wait until we press any key.System.in.read();}catch (Exception e) {e.printStackTrace();}} }15.servlet容器是用來處理請求servlet資源,并為Web客戶端填充response對象的模塊。servlet容器是org.apache.catalina.Container接口的實例。在Tomcat中,共有4種類型的容器,分別是: Engine、Host、Context和Wrapper。
16.ClientIPLoggerValve類的定義
package ex05.pyrmont.valves;import java.io.IOException; import javax.servlet.ServletRequest; import javax.servlet.ServletException; import org.apache.catalina.Request; import org.apache.catalina.Valve; import org.apache.catalina.ValveContext; import org.apache.catalina.Contained; import org.apache.catalina.Container;public class ClientIPLoggerValve implements Valve, Contained {protected Container container;public void invoke(Request request, Response response,ValveContext valveContext) throws IOException, ServletException {// Pass this request on to the next valve in our pipelinevalveContext.invokeNext(request, response);System.out.println("Client IP Logger Valve");ServletRequest sreq = request.getRequest();System.out.println(sreq.getRemoteAddr());System.out.println("------------------------");}public String getInfo() {return null;}public Container getContainer() {return container;}public void setContainer(Container container) {this.container = container;} }17.HeaderLoggerValve類的定義
package ex05.pyrmont.valves;import java.io.IOException; import java.util.Enumeration; import javax.servlet.ServletRequest; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.Request; import org.apache.catalina.Response; import org.apache.catalina.Valve; import org.apache.catalina.ValveContext; import org.apache.catalina.Contained; import org.apache.catalina.Container;public class HeaderLoggerValve implements Valve, Contained {protected Container container;public void invoke(Request request, Response response,ValveContext valveContext) throws IOException, ServletException {// Pass this request on to the next valve in our pipelinevalveContext.invokeNext(request, response);System.out.println("Header Logger Valve");ServletRequest sreq = request.getRequest();if (sreq instanceof HttpServletRequest) {HttpServletRequest hreq = (HttpServletRequest) sreq;Enumeration headerNames = hreq.getHeaderNames();while (headerNames.hasMoreElements()) {String headerName = headerNames.nextElement().toString();String headerValue = hreq.getHeader(headerName);System.out.println(headerName + ":" + headerValue);}}else System.out.println("Not an HTTP Request");System.out.println("===============================");}public String getInfo() {return null;}public Container getContainer() {return container;}public void setContainer(Container container) {this.container = container;} }18.Lifecycle接口
package org.apache.catalina; public interface Lifecycle {public static final String START_EVENT = "start";public static final String BEFORE_START_EVENT = "before_start";public static final String AFTER_START_EVENT = "after_start";public static final String STOP_EVENT = "stop";public static final String BEFORE_STOP_EVENT = "before_stop";public static final String AFTER_STOP_EVENT = "after_stop";public void addLifecycleListener(LifecycleListener listener);public LifecycleListener[] findLifecycleListeners();public void removeLifecycleListener(LifecycleListener listener);public void start() throws LifecycleException;public void stop() throws LifecycleException; }19.LifecycleEvent類的定義
package org.apache.catalina; import java.util.EventObject;public final class LifecycleEvent extends EventObject {public LifecycleEvent(Lifecycle lifecycle, String type) {this(lifecycle, type, null);}public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {super(lifecycle);this.lifecycle = lifecycle;this.type = type;this.data = data;}private Object data = null;private Lifecycle lifecycle = null;private String type = null;public Object getData() {return (this.data);}public Lifecycle getLifecycle() {return (this.lifecycle);}public String getType() {return (this.type);} }20.Logger接口的定義
package org.apache.catalina; import java.beans.PropertyChangeListener;public interface Logger {public static final int FATAL = Interger.MIN_VALUE;public static final int ERROR = 1;public static final int WARNing = 2;public static final int INFORMATION = 3;public static final int DEBUG = 4;public Container getContainer();public void setContainer(Container container);public String getInfo();public int getVerbosity();public void setVerbosity(int verbosity);public void addPropertyChangeListener(PropertyChangeListener listener);public void log(String message);public void log(Exception exception, String msg);public void log(String message, Throwable throwable);public void log(String message, int verbosity);public void log(String message, Throwable throwable, int verbosity);public void removePropertyChangeListener(PropertyChangeListener listener); }21.log()方法的實現
public void log(String msg) {// Construct the timestamp we will use, if requestedTimstamp ts = new Timestamp(System.currentTimeMillis());String tsString = ts.toString().substring(0, 19);String tsDate = tsString.substring(0, 10);// If the date has changed, switch log filesif (!date.equals(tsDate)) {synchronized (this) {if (!date.equals(tsDate)) {close();date = tsDate;open();}}}// Log this message, timestamped if necessaryif (writer != null) {if (timestamp) {writer.println(tsString + " " + msg);} else {writer.println(msg);}} }22.當調用WebappLoader類的start()方法時,會完成以下幾項重要工作:
(1) 創建一個類載入器;
(2) 設置倉庫;
(3) 設置類路徑;
(4) 設置訪問權限;
(5) 啟動一個新線程來支持自動重載.
WebappLoader類中run()方法的實現:
public void run() {if (debug >= 1)log("BACKGROUND THREAD Starting");// Loop until the termination semaphore is setwhile (!threadDone) {// Wait for our check intervalthreadSleep();if (!started)break;try {// Perform our modification checkif (!classLoader.modified())continue;}catch (Exception e) {log(sm.getString("webappLoader.failModifiedCheck"), e);continue;}// Handle a need for reloadingnotifyContext();break;}if (debug >= 1)log("BACKGROUND THREAD Stopping"); }23.Session管理
Catalina通過一個稱為Session管理器的組件來管理建立的Session對象,該組件由org.apache.catalina.Manager接口表示。Session管理器需要與一個Context容器相關聯,且必須與一個Context容器關聯。相比于其他組件,Session管理器負責創建、更新、銷毀Session對象,當有請求到來時,要回返回一個有效的Session對象。
expire()方法的實現:
public void expire(boolean notify) {//Mark this session as "being expired" if neededif (expiring)return;expiring = true;setValid(false);// Remove this session from our manager's active sessionsif (manager != null) manager.remove(this);// Unbind any objects associated with this sessionString keys[] = keys();for (int i=0; i<keys.length; i++) removeAttribute(keys[i], notify);//Notify interested session event listenersif (notify) {fireSesionEvent(Session.SESSION_DESTROYED_EVENT, null);}// Notify interested application event listeners// FIXME - ASSUMES we call listeners in reverse orderContext context = (Context) manager.getContainer();Object listeners[] = context.getApplicationListeners();if (notify && (listeners != null)) {HttpSessionEvent event = new HttpSssionEvent(getSession());for (int i=0; i<listeners.length; i++) {int j = (listeners.length - 1) - i;if (!(listeners[j] instanceof HttpSessionListener))continue;HttpSesionListener listener = (HttpSessionListener) listeners[j];try {fireContainerEvent(context, "beforeSessionDestroyed", listener);listener.sessionDestroyed(event);fireContainerEvent(context, "afterSessionDestroyed", listener);}catch (Throwable t) {try {fireContainerEvent(context, "afterSessionDestroyed", listener);} catch (Exception e) {;}// FIXME - should we do anything besides log these?log(sm.getString("standardSession.sessionEvent"), t);}}}// We have completed expire of the sessionexpiring = false;if ((manager != null) && (manger instanceof ManagerBase)) {recycle();} }24.Manager接口
Session管理器是Manager接口的實例。Manager接口的定義:
package org.apache.catalina; import java.beans.PropertyChangeListener; import java.io.IOException;public interface Manager {public Container getContainer();public void setContainer(Container container);public DefaultContext getDefaultContext();public void setDefaultContext(DefaultContext defaultContext);public boolean getDistributable();public void setDistributable(boolean distributable);public String getInfo();public int getMaxInactiveInterval(0;public void setMaxInactiveInterval(int interval);public void add(Session session);public void addPropertyChangeListener(PropertyChangeListener listener);public Session createSession();public Session findSession(String id) throws IOException;public Session[] findSessions();public void load() throws ClassNotFoundException, IOException;public void remove(Session session);public void removePropertyChangeListener(PropertyChangeListener listener);public void unload() throws IOException; }某個Context容器的Session管理器會管理該Context容器中所有活動的Session對象。這些活動的Session對象都存儲在一個名為sessions的HashMap變量中:
protected HashMap sessions = new HashMap();add()方法會將一個Session對象添加到HashMap變量sessions中,如下所示:
public void add(Session session) {synchronized (sessions) {sessions.put(session.getId(), session);} }remove()方法會將一個Session對象從HashMap變量sessions中移除,如下所示:
public void remove(Session session) {synchronized(sessions) {sessions.remove(session.getId());} }不帶參數和帶參數的findSession()方法
25.createSession()方法的實現
public Session createSession() {Session session = super.createSession();ObjectOutputStream oos = null;ByteArrayOutputStream bos = null;ByteArrayInputStream bis = null;try {bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(new BufferedOutputStream(bos));((StandardSession)session).writeObjectData(oos);oos.close();byte[] obs = bos.toByteArray();clusterSender.send(obs);if (debug > 0)log("Replicating Session: " + session.getId());}catch (IOException e) {log("An error occurred when replicating Session: " +session.getId());}return (session); }26.存儲器 Store接口的定義
package org.apache.catalina; import java.beans.PropertyChangeListener; import java.io.IOException; public interface Store{public String getInfo();public Manager getManager();public void setManager(Manager manager);public int getSize() throws IOException;public void addPropertyChangeListener(PropertyChangeListener listener);public String[] keys() throws IOException;public Session load(String id)throws ClassNotFoundException, IOException;public void remove(String id) throws IOException;public void clear() throws IOException;public void removePropertyChangeListener(PropertyChangeListener listener);public void save(Session session) throws IOException; }processExpires()方法會獲取所有活動的Session對象,檢查每個Session對象的lastAccessedTime屬性值,刪除那些長時間不活動的Session對象。方法實現如下:
protected void processExpires() {long timeNow = System.currentTimeMillis();String[] keys = null;if (!started)return;try {keys = keys();}catch (IOException e) {log(e.toString());e.printStackTrace();return;}for (int i=0; i<keys.length; i++) {try {StandardSession session = (StandardSession) load(keys[i]);if (!session.isValid())continue;int maxInactiveInterval = session.getMaxInactiveInterval();if (maxInactiveInterval < 0) continue;int timeIdel = // Truncate, do not round up(int) ((timeNow - session.getLastAccessedTime()) / 1000L);if (timeIdle >= maxInactiveInterval) {if (( (persistentManagerBase) manager).isLoaded(keys[i])) {// recycle old backup sessionsession.recycle();}else {//expire swapped out sessionsession.expire();}remove(session.getId());}}catch (IOException e) {log( e.toString());e.printStackTrace();}catch (ClassNotFoundException e) {log(e.toString());e.printStackTrace();}} }27.StandardServer類中initialize()方法的實現
public void initialize() throws LifecycleException {if (initialized) throw new LifecycleException {sm.getString("standardServer.initialize.initialized"));initialized = true;// Initialize our defined Servicesfor (int i=0; i<services.length; i++) {services[i].initialize();} }start()方法的實現:
public void start() throws LifecycleException {// Validate and update our current componeent state if (started) throw new LifecycleException(sm.getString("standardServer.start.started"));// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);lifecycle.fireLifecycleEvent(START_EVENT, null);started = true;// Start out defined Servicessynchronized (services) {for (int i=0; i<services.length; i++) {if (services[i] instanceof Lifecycle)((Lifecycle) services[i]).start();}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); }start()方法使用布爾變量 start來防止服務器組件重復啟動。stop()方法會重置這個變量。
stop()方法:
public void stop() throws LifecycleException {// Validate and update our current component state if (!started) throw new LifecycleException(sm.getString("standardServer.stop.notStarted"));// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);lifecycle.fireLifecycleEvent(STOP_EVENT, null);started = false;// Stop our defined Servicesfor (int i=0; i<services.length; i++) {if (services[i] instanceof Lifecycle)((Lifecycle) services[i]).stop();}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); }await()方法負責等待關閉整個Tomcat部署的命令。await()方法的實現:
/*** Wait until a proper shutdown command is received, then return.*/ public void await() {// Set up a server socket to awit onServerSocket serverSocket = null;try {serverSocket = new ServerSocket(port, 1,InetAddress.getByName("127.0.0.1"));}catch (IOException e) {System.err.println("StandardServer.await: create[" + port + "]: " + e);e.printStackTrace();System.exit(1);}// Loop waiting for a connection and a valid commandwhile (true) {// Wait for the next connectionSocket socket = null;InputStream stream = null;try {socket = serverSocket.accept();socket.setSoTimeout(10 * 1000); //Ten secondsstream = socket.getInputStream();}catch (AccessControlException ace) {System.err.println("StandardServer.accept security exception: " +ace.getMessage());continue;}catch (IOException e) {System.err.println("StandardServer.await: accept: "+ e);e.printStackTrace();System.exit(1);}// Read a set of characters from the socketStringBuffer command = new StringBuffer();int expected = 1024; //Cut off to avoid Dos attackwhile (expected < shutdown.length()) {if (random == null)random = new Random(System.currentTimeMillis());expected += (random.nextInt() % 1024);}while (expected > 0) {int ch = -1;try {ch = stream.read();}catch (IOException e) {System.err.println("StandardServer.await: read: " + e);e.printStackTrace();ch = -1;}if (ch < 32) // Control character or EOF terminates loopbreak;command.append((char) ch);expected--;}// Close the socket now that we are done with ittry {socket.close();}catch (IOException e) {;}// Match against our command stringboolean match = command.toString().equals(shutdown);if (match) {break;}else System.err.println("StandardServer.await: Invalid command '" +command.toString() + "' received");}// CLose the server socket and returntry {serverSocket.close();} catch (IOException e) {;}}?
總結
以上是生活随笔為你收集整理的<深入剖析Tomcat>摘抄的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《TOMCAT权威指南》摘抄
- 下一篇: 渗透测试之通过代码审计打点