`

MiniTomcat - How Tomcat Works 2: Servlet Container

阅读更多

开发一个简单的Servlet容器

1. Servlet编程是通过javax.servlet和javax.servlet.http这两个包的类和接口来实现的。其中一个至关重要的就是javax.servlet.Servlet接口了。所有的servlet必须实现实现或者继承实现该接口的类。

    Servlet接口有五个方法:

//在servlet类已经初始化之后,init方法将会被servlet容器所调用
public void init(ServletConfig config) throws ServletException
//servlet容器为servlet请求调用它的service方法
public void service(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException
//当从服务中移除一个servlet实例的时候,servlet容器调用destroy方法
public void destroy()
public ServletConfig getServletConfig()
public java.lang.String getServletInfo()

 
    当第一次调用servlet的时候,加载该servlet类并调用servlet的init方法(仅仅一次)。
    对每次请求,构造一个javax.servlet.ServletRequest实例和一个javax.servlet.ServletResponse实例。
    调用servlet的service方法,同时传递ServletRequest和ServletResponse对象。
    当servlet类被关闭的时候,调用servlet的destroy方法并卸载servlet类。

 

 

2. Simple Servlet由6个类组成

    HttpServer1:处理静态资源和动态Servlet请求

import java.net.*;
import java.io.*;
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);
            }
        }
    }
}

 

    Request:实现javax.servlet.ServletRequest接口 

import java.io.*;
import java.util.*;
import javax.servlet.*;
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 { }
}

  

    Response:实现javax.servlet.ServletResponse

import java.io.*;
import java.util.*;
import javax.servlet.*;
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);
            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) { }
}

 

    StaticResourceProcessor:用来提供静态资源请求

import java.io.IOException;
public class StaticResourceProcessor {
    public void process(Request request, Response response) {
    try {
        response.sendStaticResource();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    }
}

 

    ServletProcessor1:用于处理servlet的HTTP请求

import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.io.File;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class ServletProcessor1 {
    public void process(Request request, Response response) {
        String uri = request.getUri();
        String servletName = uri.substring(uri.lastIndexOf("/") + 1);
        URLClassLoader loader = null;
        try {
            // create a URLClassLoader
            // urls是一个java.net.URL的对象数组,这些对象指向了加载类时候查找的位置
            URL[] urls = new URL[1];
            URLStreamHandler streamHandler = null;
            File classPath = new File(Constants.WEB_ROOT);
            // the forming of repository is taken from the
            // createClassLoader method in
            // org.apache.catalina.startup.ClassLoaderFactory
            // 在一个servlet容器里边,一个类加载器可以找到servlet的地方被称为资源库(repository)
            String repository =(new URL("file", null, classPath.getCanonicalPath() +
                File.separator)).toString() ;
            // the code for forming the URL is taken from
            // the addRepository method in
            // org.apache.catalina.loader.StandardClassLoader.
            urls[0] = new URL(null, repository, streamHandler);
            loader = new URLClassLoader(urls);
        }
        catch (IOException e) {
            System.out.println(e.toString() );
        }
        Class myClass = null;
        try {
            myClass = loader.loadClass(servletName);
        }
        catch (ClassNotFoundException e) {
            System.out.println(e.toString());
        }
        Servlet servlet = null;
        try {
            servlet = (Servlet) myClass.newInstance();
            servlet.service((ServletRequest) request,
            (ServletResponse) response);
        }
        catch (Exception e) {
            System.out.println(e.toString());
        }
        catch (Throwable e) {
            System.out.println(e.toString());
        }
    }
}

 

    Constants:保存WEB_ROOT

import java.io.File;
public class Constants {
    public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator  + "webroot";
}

 

 

3. Facade

    将request对象向上转型为ServletRequest,交给service方法。但如果Servlet的开发者清楚tomcat的内部设计,

    那么他就可以在service方法中将request向下"还原为"Request对象。Request类提供了许多tomcat内部使用的功

    能,譬如解析http流。如果胡乱使用,结果很严重。为了避免该问题,tomcat采用了Facade设计模式,即通过一个

    RequestFacade类(实现了ServletRequest接口),替换Request类传递给service方法。而在RequestFacade

    内部,保存我们的request对象,外部只能通过调用RequestFacade实现了的ServletRequest接口的方法,间接的

    使用Request的"部分功能",不能调用Request的一些内部方法,从而优雅的解决了上述问题。

 

    RequestFacade类

public class RequestFacade implements ServletRequest {
    private ServleLRequest request = null;
    public RequestFacade(Request request) {
        this.request = request;
    }
    /* implementation of the ServletRequest*/
    public Object getAttribute(String attribute) {
        return request.getAttribute(attribute);
    }
    public Enumeration getAttributeNames() {
        return request.getAttributeNames();
    }
    ...
}

 

    ServletProcessor2类

Servlet servlet = null;
RequestFacade requestFacade = new RequestFacade(request);
ResponseFacade responseFacade = new ResponseFacade(response);
try {
    servlet = (Servlet) myClass.newInstance();
    servlet.service((ServletRequest) requestFacade,(ServletResponse)responseFacade);
}

 

    ResponseFacade类和RequestFacade类似 

 

分享到:
评论

相关推荐

    how-tomcat-works-master_howtomcatworks_

    "how-tomcat-works-master_howtomcatworks_"是一个关于Tomcat工作原理的源码分析项目,经过整理后可以在IntelliJ IDEA中直接运行,为开发者提供了一手的实践平台。 首先,我们要了解Tomcat的核心组件。Tomcat主要由...

    How Tomcat Works 中文版.pdf

    《How Tomcat Works》中文版一书详细剖析了Tomcat服务器的内部工作机制。该书基于Tomcat 4.1.12和5.0.18两个版本,深入讲解了其servlet容器的架构和运作原理,尤其是代号为Catalina的核心组件。 Tomcat是一个开源的...

    How Tomcat Works 中文版+例程源码

    《How Tomcat Works》是一本深入探讨Apache Tomcat工作原理的书籍,中文版的提供使得国内开发者能够更方便地理解这一流行的开源Java Servlet容器。这本书不仅涵盖了Tomcat的基础知识,还详细解析了其内部机制,对于...

    How Tomcat Works中文

    ### How Tomcat Works中文版深度解析 #### 一、引言与概述 《How Tomcat Works》是一本针对Apache Tomcat服务器内部工作机制进行深入剖析的专业书籍。本书详细介绍了Tomcat 4.1.12和5.0.18两个版本的内部结构与...

    How Tomcat Works: A Guide to Developing Your Own Java Servlet Container

    tomcat的版本4和版本5 2 章节简介 2 第1章 一个简单的Web服务器 3 1.1 The Hypertext Transfer Protocol (HTTP) 3 1.2 HTTP Request 3 1.3 HTTP Response 4 1.4 Socket类 4 1.5 ServerSocket类 5 1.6 应用举例 5 第2...

    how-tomcat-works中文 doc文档

    Tomcat作为一款开源的Servlet容器,被广泛应用于Java Web开发之中。它不仅能够运行Java Servlet,还支持JSP技术,是学习Java Web开发的理想平台之一。本文档将对Tomcat的工作原理进行深入探讨,并通过分析其核心组件...

    how tomcat works

    《How Tomcat Works》这本书的目的是为了让读者能够深入理解Tomcat的工作机制,从而能够更好地开发和配置Tomcat服务器,甚至加入其开发团队。首先,书中强调了Tomcat是一个开源的、广泛使用的Java Servlet容器,其中...

    How Tomcat Works 中文版

    《How Tomcat Works中文版》这本书是一本深入探讨Apache Tomcat服务器工作原理的专著。Apache Tomcat服务器,或简称为Tomcat,是世界上广泛使用的Java Servlet容器和JavaServer Pages(JSP)引擎,负责处理基于Java...

    HowTomcatWorks(书和源码)

    《How Tomcat Works》是一本深入解析Apache Tomcat工作原理的书籍,同时也包含了源码,为读者提供了理论与实践相结合的深入学习体验。Tomcat是一款广泛使用的开源Java Servlet容器,它是Apache软件基金会 Jakarta...

    how tomcat works 中文版及源码

    《How Tomcat Works》是一本深入解析Apache Tomcat工作原理的书籍,中文版的出现使得国内开发者能够更方便地理解这个流行的Java Servlet容器。Tomcat是开源软件,它实现了Java Servlet和JavaServer Pages(JSP)规范...

    How Tomcat Works 英文版 带书签

    This book dissects Tomcat 4.1.12 and 5.0.18 and explains the internal workings of its free, open source, and most popular servlet container code-named Catalina. Tomcat is a complex system, consisting...

Global site tag (gtag.js) - Google Analytics