您的位置:首页 > 运维架构 > Tomcat

how tomcat works<三>

2015-03-10 17:33 561 查看
Catalina有两个主要的模块:connector和container,connector接收http请求,发送给container进行处理。container必须创建HttpServletRequest和HttpServletResponse的实例,然后传递给被调用的servlet的service方法。在这篇文章的应用中,connector解析HTTP请求头,并允许servlet获取headers, cookies, parameter names/values。

本篇的应用由三个模块组成:connector, startup, 和core.

startup模块仅包含一个类:BootStrap,它是应用的入口

connector模块分为5个类别:

connector 和它的支持(supporting )类(HttpConnector 和HttpProcessor )
代表HTTP 请求的类(HttpRequest )及 其支持类
代表HTTP 响应的类(HttpResponse )及其支持类
门面(Facade )类(HttpRequestFacade 和HttpResponseFacade )
Constant 类

core模块包含两个类: ServletProcessor and StaticResourceProcessor



在这章的应用中,监听HTTP请求的任务交给了HttpConnector类,创建http请求和响应的任务交给了HttpProcessor类。HttpRequest类代表一个请求,HttpRespons代表一个响应。HttpRequest必须实现javax.servlet.http.HttpServletRequest接口。一个HttpRequest对象将会被转换成(cast)HttpServletRequest的实例然后传递给被请求的servlet的service方法。因此,每个HttpRequest的实例必须拥有合适的成员,被分配给HttpRequest的值有:URI,
query string, parameters, cookies and 其他的 headers

SocketInputStream类包含两个重要的方法:readRequestLine和readHeader。readRequestLine返回请求字符串的第一行,readHeader用来获取名值对。

本篇的应用包含如下的结构:

 Starting the Application

 The Connector

 Creating an HttpRequest Object

 Creating an HttpResponse Object

 Static resource processor and servlet processor

 Running the Application

Starting the Application

ex03.pyrmont.startup.Bootstrap类为起点类,源代码如下:

[java] view
plaincopy

package ex03.pyrmont.startup;

import ex03.pyrmont.connector.http.HttpConnector;

public final class Bootstrap {

public static void main(String[] args) {

HttpConnector connector = new HttpConnector();

connector.start();

}

}

[java] view
plaincopy

HttpConnector类的main方法实例化一个HttpConnector,然后调用它的start方法,启动一个线程

[java] view
plaincopy

[java] view
plaincopy

<pre name="code" class="java">HttpConnector类的代码如下:</pre><pre name="code" class="java"><pre name="code" class="java">package ex03.pyrmont.connector.http;

import java.io.IOException;

import java.net.InetAddress;

import java.net.ServerSocket;

import java.net.Socket;

public class HttpConnector implements Runnable {

boolean stopped;

private String scheme = "http";

public String getScheme() {

return scheme;

}

public void run() {

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);

}

while (!stopped) {

// Accept the next incoming connection from the server socket

Socket socket = null;

try {

socket = serverSocket.accept();

}

catch (Exception e) {

continue;

}

// Hand this socket off to an HttpProcessor

HttpProcessor processor = new HttpProcessor(this);

processor.process(socket);

}

}

public void start() {

Thread thread = new Thread(this);

thread.start();

}

}</pre><br>

我们来看看HttpProcessor的processor方法:<p></p>

<pre></pre>

<pre name="code" class="java"><pre name="code" class="java"> 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 parse

request = new HttpRequest(input);

// create HttpResponse object

response = 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 socket

socket.close();

// no shutdown for this application

}

catch (Exception e) {

e.printStackTrace();

}

}

</pre><br>

<span style="font-size:24px"><strong><br>

创建HttpRequest对象 </strong></span>

<pre></pre>

<pre name="code" class="java"><span style="font-size:14px;">httpRequest类实现了javax.servlet.http.HttpServletRequest接口,类图如下:</span></pre><pre name="code" class="java"><img src="http://img.blog.csdn.net/20130903030707843?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2VuamluZ3l1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

</pre><pre name="code" class="java">HttpRequest的代码如下:<pre name="code" class="java">package ex03.pyrmont.connector.http;

/** this class copies methods from org.apache.catalina.connector.HttpRequestBase

* and org.apache.catalina.connector.http.HttpRequestImpl.

* The HttpRequestImpl class employs a pool of HttpHeader objects for performance

* These two classes will be explained in Chapter 4.

*/

import ex03.pyrmont.connector.RequestStream;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

import javax.servlet.http.Cookie;

import javax.servlet.RequestDispatcher;

import javax.servlet.ServletInputStream;

import java.security.Principal;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.IOException;

import java.io.BufferedReader;

import java.io.UnsupportedEncodingException;

import java.net.InetAddress;

import java.net.Socket;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.Date;

import java.util.Enumeration;

import java.util.HashMap;

import java.util.Locale;

import java.util.Map;

import org.apache.catalina.util.Enumerator;

import org.apache.catalina.util.ParameterMap;

import org.apache.catalina.util.RequestUtil;

public class HttpRequest implements HttpServletRequest {

private String contentType;

private int contentLength;

private InetAddress inetAddress;

private InputStream input;

private String method;

private String protocol;

private String queryString;

private String requestURI;

private String serverName;

private int serverPort;

private Socket socket;

private boolean requestedSessionCookie;

private String requestedSessionId;

private boolean requestedSessionURL;

/**

* The request attributes for this request.

*/

protected HashMap attributes = new HashMap();

/**

* The authorization credentials sent with this Request.

*/

protected String authorization = null;

/**

* The context path for this request.

*/

protected String contextPath = "";

/**

* The set of cookies associated with this Request.

*/

protected ArrayList cookies = new ArrayList();

/**

* An empty collection to use for returning empty Enumerations. Do not

* add any elements to this collection!

*/

protected static ArrayList empty = new ArrayList();

/**

* The set of SimpleDateFormat formats to use in getDateHeader().

*/

protected SimpleDateFormat formats[] = {

new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),

new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),

new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)

};

/**

* The HTTP headers associated with this Request, keyed by name. The

* values are ArrayLists of the corresponding header values.

*/

protected HashMap headers = new HashMap();

/**

* The parsed parameters for this request. This is populated only if

* parameter information is requested via one of the

* <code>getParameter()</code> family of method calls. The key is the

* parameter name, while the value is a String array of values for this

* parameter.

* <p>

* <strong>IMPLEMENTATION NOTE</strong> - Once the parameters for a

* particular request are parsed and stored here, they are not modified.

* Therefore, application level access to the parameters need not be

* synchronized.

*/

protected ParameterMap parameters = null;

/**

* Have the parameters for this request been parsed yet?

*/

protected boolean parsed = false;

protected String pathInfo = null;

/**

* The reader that has been returned by <code>getReader</code>, if any.

*/

protected BufferedReader reader = null;

/**

* The ServletInputStream that has been returned by

* <code>getInputStream()</code>, if any.

*/

protected ServletInputStream stream = null;

public HttpRequest(InputStream input) {

this.input = input;

}

public void addHeader(String name, String value) {

name = name.toLowerCase();

synchronized (headers) {

ArrayList values = (ArrayList) headers.get(name);

if (values == null) {

values = new ArrayList();

headers.put(name, values);

}

values.add(value);

}

}

/**

* Parse the parameters of this request, if it has not already occurred.

* If parameters are present in both the query string and the request

* content, they are merged.

*/

protected void parseParameters() {

if (parsed)

return;

ParameterMap results = parameters;

if (results == null)

results = new ParameterMap();

results.setLocked(false);

String encoding = getCharacterEncoding();

if (encoding == null)

encoding = "ISO-8859-1";

// Parse any parameters specified in the query string

String queryString = getQueryString();

try {

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");

}

}

// Store the final results

results.setLocked(true);

parsed = true;

parameters = results;

}

public void addCookie(Cookie cookie) {

synchronized (cookies) {

cookies.add(cookie);

}

}

/**

* Create and return a ServletInputStream to read the content

* associated with this Request. The default implementation creates an

* instance of RequestStream associated with this request, but this can

* be overridden if necessary.

*

* @exception IOException if an input/output error occurs

*/

public ServletInputStream createInputStream() throws IOException {

return (new RequestStream(this));

}

public InputStream getStream() {

return input;

}

public void setContentLength(int length) {

this.contentLength = length;

}

public void setContentType(String type) {

this.contentType = type;

}

public void setInet(InetAddress inetAddress) {

this.inetAddress = inetAddress;

}

public void setContextPath(String path) {

if (path == null)

this.contextPath = "";

else

this.contextPath = path;

}

public void setMethod(String method) {

this.method = method;

}

public void setPathInfo(String path) {

this.pathInfo = path;

}

public void setProtocol(String protocol) {

this.protocol = protocol;

}

public void setQueryString(String queryString) {

this.queryString = queryString;

}

public void setRequestURI(String requestURI) {

this.requestURI = requestURI;

}

/**

* Set the name of the server (virtual host) to process this request.

*

* @param name The server name

*/

public void setServerName(String name) {

this.serverName = name;

}

/**

* Set the port number of the server to process this request.

*

* @param port The server port

*/

public void setServerPort(int port) {

this.serverPort = port;

}

public void setSocket(Socket socket) {

this.socket = socket;

}

/**

* Set a flag indicating whether or not the requested session ID for this

* request came in through a cookie. This is normally called by the

* HTTP Connector, when it parses the request headers.

*

* @param flag The new flag

*/

public void setRequestedSessionCookie(boolean flag) {

this.requestedSessionCookie = flag;

}

public void setRequestedSessionId(String requestedSessionId) {

this.requestedSessionId = requestedSessionId;

}

public void setRequestedSessionURL(boolean flag) {

requestedSessionURL = flag;

}

/* implementation of the HttpServletRequest*/

public Object getAttribute(String name) {

synchronized (attributes) {

return (attributes.get(name));

}

}

public Enumeration getAttributeNames() {

synchronized (attributes) {

return (new Enumerator(attributes.keySet()));

}

}

public String getAuthType() {

return null;

}

public String getCharacterEncoding() {

return null;

}

public int getContentLength() {

return contentLength ;

}

public String getContentType() {

return contentType;

}

public String getContextPath() {

return contextPath;

}

public Cookie[] getCookies() {

synchronized (cookies) {

if (cookies.size() < 1)

return (null);

Cookie results[] = new Cookie[cookies.size()];

return ((Cookie[]) cookies.toArray(results));

}

}

public long getDateHeader(String name) {

String value = getHeader(name);

if (value == null)

return (-1L);

// Work around a bug in SimpleDateFormat in pre-JDK1.2b4

// (Bug Parade bug #4106807)

value += " ";

// Attempt to convert the date header in a variety of formats

for (int i = 0; i < formats.length; i++) {

try {

Date date = formats[i].parse(value);

return (date.getTime());

}

catch (ParseException e) {

;

}

}

throw new IllegalArgumentException(value);

}

public String getHeader(String name) {

name = name.toLowerCase();

synchronized (headers) {

ArrayList values = (ArrayList) headers.get(name);

if (values != null)

return ((String) values.get(0));

else

return null;

}

}

public Enumeration getHeaderNames() {

synchronized (headers) {

return (new Enumerator(headers.keySet()));

}

}

public Enumeration getHeaders(String name) {

name = name.toLowerCase();

synchronized (headers) {

ArrayList values = (ArrayList) headers.get(name);

if (values != null)

return (new Enumerator(values));

else

return (new Enumerator(empty));

}

}

public ServletInputStream getInputStream() throws IOException {

if (reader != null)

throw new IllegalStateException("getInputStream has been called");

if (stream == null)

stream = createInputStream();

return (stream);

}

public int getIntHeader(String name) {

String value = getHeader(name);

if (value == null)

return (-1);

else

return (Integer.parseInt(value));

}

public Locale getLocale() {

return null;

}

public Enumeration getLocales() {

return null;

}

public String getMethod() {

return method;

}

public String getParameter(String name) {

parseParameters();

String values[] = (String[]) parameters.get(name);

if (values != null)

return (values[0]);

else

return (null);

}

public Map getParameterMap() {

parseParameters();

return (this.parameters);

}

public Enumeration getParameterNames() {

parseParameters();

return (new Enumerator(parameters.keySet()));

}

public String[] getParameterValues(String name) {

parseParameters();

String values[] = (String[]) parameters.get(name);

if (values != null)

return (values);

else

return null;

}

public String getPathInfo() {

return pathInfo;

}

public String getPathTranslated() {

return null;

}

public String getProtocol() {

return protocol;

}

public String getQueryString() {

return queryString;

}

public BufferedReader getReader() throws IOException {

if (stream != null)

throw new IllegalStateException("getInputStream has been called.");

if (reader == null) {

String encoding = getCharacterEncoding();

if (encoding == null)

encoding = "ISO-8859-1";

InputStreamReader isr =

new InputStreamReader(createInputStream(), encoding);

reader = new BufferedReader(isr);

}

return (reader);

}

public String getRealPath(String path) {

return null;

}

public String getRemoteAddr() {

return null;

}

public String getRemoteHost() {

return null;

}

public String getRemoteUser() {

return null;

}

public RequestDispatcher getRequestDispatcher(String path) {

return null;

}

public String getScheme() {

return null;

}

public String getServerName() {

return null;

}

public int getServerPort() {

return 0;

}

public String getRequestedSessionId() {

return null;

}

public String getRequestURI() {

return requestURI;

}

public StringBuffer getRequestURL() {

return null;

}

public HttpSession getSession() {

return null;

}

public HttpSession getSession(boolean create) {

return null;

}

public String getServletPath() {

return null;

}

public Principal getUserPrincipal() {

return null;

}

public boolean isRequestedSessionIdFromCookie() {

return false;

}

public boolean isRequestedSessionIdFromUrl() {

return isRequestedSessionIdFromURL();

}

public boolean isRequestedSessionIdFromURL() {

return false;

}

public boolean isRequestedSessionIdValid() {

return false;

}

public boolean isSecure() {

return false;

}

public boolean isUserInRole(String role) {

return false;

}

public void removeAttribute(String attribute) {

}

public void setAttribute(String key, Object value) {

}

/**

* Set the authorization credentials sent with this request.

*

* @param authorization The new authorization credentials

*/

public void setAuthorization(String authorization) {

this.authorization = authorization;

}

public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException {

}

public String getLocalAddr() {

// TODO Auto-generated method stub

return null;

}

public String getLocalName() {

// TODO Auto-generated method stub

return null;

}

public int getLocalPort() {

// TODO Auto-generated method stub

return 0;

}

public int getRemotePort() {

// TODO Auto-generated method stub

return 0;

}

}

</pre><br>

<pre></pre>

<pre name="code" class="java">HttpRequest类包含如下子内容:</pre><pre name="code" class="java"><ul style="margin: 0px 0px 1.5em; padding: 0px;"><li style="margin: 0px 0px 0.25em 30px; padding: 0px;">读取套接字的输入流</li><li style="margin: 0px 0px 0.25em 30px; padding: 0px;">解析请求行</li><li style="margin: 0px 0px 0.25em 30px; padding: 0px;">解析headers</li><li style="margin: 0px 0px 0.25em 30px; padding: 0px;">解析cookies</li><li style="margin: 0px 0px 0.25em 30px; padding: 0px;">获取请求参数</li></ul></pre>

<pre></pre>

<pre name="code" class="java"></pre><br>

<p></p>

<p><br>

</p>

</pre></pre></pre>

转自:http://blog.csdn.net/wenjingyu/article/details/10952597
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: