zoukankan      html  css  js  c++  java
  • Tomcat源码学习(10)How Tomcat works(转)

    HttpServer1类

        这个应用程序里边的HttpServer1类类似于第1章里边的简单服务器应用程序的HttpServer类。不过,在这个应用程序里边HttpServer1类可以同时提供静态资源和servlet。要请求一个静态资源,你可以在你的浏览器地址栏或者网址框里边敲入一个URL:
    http://machineName:port/staticResource
        就像是在第1章提到的,你可以请求一个静态资源。
        为了请求一个servlet,你可以使用下面的URL:
    http://machineName:port/servlet/servletClass
        因此,假如你在本地请求一个名为PrimitiveServlet的servlet,你在浏览器的地址栏或者网址框中敲入:
    http://localhost:8080/servlet/PrimitiveServlet
        servlet容器可以就提供PrimitiveServlet了。不过,假如你调用其他servlet,如ModernServlet,servlet容器将会抛出一个异常。在以下各章中,你将会建立可以处理这两个情况的程序。
        HttpServer1类显示在Listing 2.2中。
             Listing 2.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 {
         /** WEB_ROOT is the directory where our HTML and other files reside.
         * For this package, WEB_ROOT is the "webroot" directory under the
         * working directory.
         * The working directory is the location in the file system
         * from where the java command was invoked.
         */
         // shutdown command
         private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
         // the shutdown command received
         private 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 request
             while (!shutdown) {
                 Socket socket = null;
                 InputStream input = null;
                 OutputStream output = null;
                 try {
                     socket = serverSocket.accept();
                     input = socket.getInputstream();
                     output = socket.getOutputStream();
                     // create Request object and parse
                     Request request = new Request(input);
                     request.parse();
                     // create Response object
                     Response 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 {
                         StaticResoureProcessor processor =
                         new StaticResourceProcessor();
                         processor.process(request, response);
                     }
                     // Close the socket
                     socket.close();
                     //check if the previous URI is a shutdown command
                     shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
                 }
                 catch (Exception e) {
                     e.printStackTrace();
                     System.exit(1);
                 }
             }
         }
    }
        类的await方法等待HTTP请求直到一个shutdown命令给发出,让你想起第1章的await方法。Listing 2.2的await方法和第1章的区别是,在Listing 2.2里边,请求可以分发给一个StaticResourceProcessor或者一个ServletProcessor。假如URI包括字符串/servlet/的话,请求将会转发到后面去。
        不然的话,请求将会传递给StaticResourceProcessor实例 instance. 请注意,这部分在Listing 2.2中灰暗显示类的await方法等待HTTP请求直到一个shutdown命令给发出,让你想起第1章的await方法。Listing 2.2的await方法和第1章的区别是,在Listing 2.2里边,请求可以分发给一个StaticResourceProcessor或者一个ServletProcessor。假如URI包括字符串/servlet/的话,请求将会转发到后面去。
        不然的话,请求将会传递给StaticResourceProcessor实例 instance. 请注意,这部分在Listing 2.2中灰暗显示。

    Request类

        servlet的service方法从servlet容器中接收一个javax.servlet.ServletRequest实例和一个javax.servlet.ServletResponse实例。这就是说对于每一个HTTP请求,servlet容器必须构造一个ServletRequest对象和一个ServletResponse对象并把它们传递给正在服务的servlet的service方法。
        ex02.pyrmont.Request类代表一个request对象并被传递给servlet的service方法。就本身而言,它必须实现javax.servlet.ServletRequest接口。这个类必须提供这个接口所有方法的实现。不过,我们想要让它非常简单并且仅仅提供实现其中一些方法,我们在以下各章中再实现全部的方法。要编译Request类,你需要把这些方法的实现留空。假如你看过Listing 2.3中的Request类,你将会看到那些需要返回一个对象的方法返回了null
             Listing 2.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 socket
             StringBuffer 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 BufferedReader getReader() throws IOException {
             return null;
         }
         public String getRemoteAddr() {
             return null;
         }
         public String getRemoteHost() {
             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 { }
    }
        另外,Request类仍然有在第1章中讨论的parse和getUri方法。

    Response类

        在Listing 2.4列出的ex02.pyrmont.Response类,实现了javax.servlet.ServletResponse。就本身而言,这个类必须提供接口里边的所有方法的实现。类似于Request类,我们把除了getWriter之外的所有方法的实现留空。
             Listing 2.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 Reason-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) { }
    }
        在getWriter方法中,PrintWriter类的构造方法的第二个参数是一个布尔值表明是否允许自动刷新。传递true作为第二个参数将会使任何println方法的调用都会刷新输出(output)。不过,print方法不会刷新输出。
        因此,任何print方法的调用都会发生在servlet的service方法的最后一行,输出将不会被发送到浏览器。这个缺点将会在下一个应用程序中修复。
        Response类还拥有在第1章中谈到的sendStaticResource方法。

    StaticResourceProcessor类

        ex02.pyrmont.StaticResourceProcessor类用来提供静态资源请求。唯一的方法是process方法。Listing 2.5给出了StaticResourceProcessor类。
             Listing 2.5: StaticResourceProcessor类
    package ex02.pyrmont;
    import java.io.IOException;
    public class StaticResourceProcessor {
         public void process(Request request, Response response) {
         try {
             response.sendStaticResource();
         }
         catch (IOException e) {
             e.printStackTrace();
         }
         }
    }
        process方法接收两个参数:一个ex02.pyrmont.Request实例和一个ex02.pyrmont.Response实例。这个方法只是简单的呼叫Response对象的sendStaticResource方法。
  • 相关阅读:
    vue 优化hash持久化缓存
    用vue的抽象组件来做一个防止img标签url为空或url地址出错的验证
    读源码学会一些编程小技巧
    webpack编译后的代码如何在浏览器执行
    vue@cli3 public目录下的静态图片,如何使用在css类文件中(sass可行,纯css不行)
    vue@cli3 项目模板怎么使用public目录下的静态文件,找了好久都不对,郁闷!
    vscode如何配置ts的lint,如何配置才能让eslint和prettier不冲突一键格式化代码(vue开发使用)
    rollup 使用babel7版本的插件rollup-plugin-babel,rollup-plugin-babel使用报错解决办法。
    深入研究webpack之Tree Shaking相关属性sideEffects用处
    前端性能优化之http缓存
  • 原文地址:https://www.cnblogs.com/macula7/p/1960628.html
Copyright © 2011-2022 走看看