[深入剖析Tomcat]一个简单的servlet容器实现

本文为读《深入剖析Tomcat》第2章做的笔记、写的代码、做的分析。作者是菜鸟,谨慎参考

  1. 实现流程图
    这里写图片描述

  2. HttpServer类:

public class HttpServer1 {
    private static String SHUT_DOWN="shutdown";
    public static void main(String[] args){
        HttpServer1 server=new HttpServer1();
        server.await();
    }
    private void await() {
        ServerSocket server=null;
        int port=806;
        try {
            server=new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
        } catch (Exception e) {
            e.printStackTrace();
        }

        boolean shutdown=false;
        while(!shutdown){
            Socket socket;
            InputStream input;
            OutputStream out;
            try {
                socket = server.accept();
                input=socket.getInputStream();
                out=socket.getOutputStream();
                Request req=new Request(input);
                req.parse();

                Response res=new Response(out);
                res.setRequest(req);

                if(req.getUri().startsWith("/servlet/")){
                    ServletProcessor1 processor=new ServletProcessor1();
                    processor.process(req,res);
                }else{
                    StaticResourceProcessor processor=new StaticResourceProcessor();
                    processor.process(req, res);
                }
                socket.close();
                shutdown=req.getUri().equals(SHUT_DOWN);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

3 . Response类的主要方法

public class Response implements ServletResponse {
    private OutputStream out;
    private Request req;
    private static int BUFFER_SIZE = 1024;
    public Response(OutputStream out) {
        this.out = out;
    }
    public void setRequest(Request req) {
        this.req = req;
    }
    public void sendStaticReSource() throws IOException {
        System.out.println("访问的资源为"+Constants.WEB_ROOT + req.getUri());
        File file = new File(Constants.WEB_ROOT + req.getUri());
        FileInputStream fis = null;
        byte[] buffer = new byte[1024];
        int n = -1;
        try {
            if (file.exists()) {
                System.out.println("该资源存在");
                fis = new FileInputStream(file);
                n = fis.read(buffer, 0, BUFFER_SIZE);
                while (n != -1) {
                    out.write(buffer, 0, n);
                    n = fis.read(buffer, 0, BUFFER_SIZE);
                }

            } else {
                System.out.println("该资源不存在");
                String msg = "msg error! file does not exist.";
                out.write(msg.getBytes());
            }
        } catch (IOException e) {
        }finally{
            if(fis!=null)
                fis.close();
        }
    }
    public PrintWriter getWriter() throws IOException{
        //调用println会自动刷新,调用print不会自动刷新
        PrintWriter writer =new PrintWriter(out,true);
        return writer;
    }
}

4 . Request的主要方法:

public class Request implements ServletRequest{
    private final static int BUFFER_SIZE=2048;
    private InputStream input;
    private String uri;
    public Request(InputStream input) {
        this.input=input;
    }
    public void parse() {
        byte[] buffers=new byte[BUFFER_SIZE];
        int n;
        try {
            n = input.read(buffers, 0, BUFFER_SIZE);
        } catch (IOException e) {
            e.printStackTrace();
            n=-1;
        }
        StringBuffer sb=new StringBuffer();
        for(int i=0;i<n;i++){
            sb.append((char)buffers[i]);
        }
        System.out.println("解析得到request:");
        System.out.println(sb);
        uri=parseUri(sb.toString());
        System.out.println("解析request中的uri:"+uri);
    }
    private String parseUri(String str){
        int index1,index2;
        index1=str.indexOf(' ');
        while(index1!=-1){
            index2=str.indexOf(' ', index1+1);
            if(index2-index1>0)
                return str.substring(index1+1,index2);
        }
        return null;
    }
    public  String getUri(){
        return uri;
    }
}
  1. ServletProcessor类:
public class ServletProcessor1 {
    public void process(Request req,Response res){
        String uri =req.getUri();
        String servletName=uri.substring(uri.lastIndexOf('/')+1);
        //URLCLassLoader为ClassLoader的直接子类
        //用它的loadClass()方法来载入servlet类
        URLClassLoader loader=null;
        try {
        URL[] urls=new URL[1];
        URLStreamHandler streamHandler=null;
        File classPath=new File(Constants.WEB_ROOT);
        String repository=(new URL("file",null,classPath.getCanonicalPath()
                +File.separator)).toString();
        System.out.println("servlet的目录repository:"+repository);
        //使用streamHandler的因为URL重载中,第3个参数不同
        //streamHandler将其区分,repository为servlet的目录
        urls[0]=new URL(null,repository,streamHandler);
        //urls为URL对象数组,每个URL对象都指明了类载入器在哪里查找类
        //若URL以“/”结尾,则表明其指向一个目录,否则为指向一个jar文件
        //根据需要载入器会下载这个jar文件
        //在servlet容器中,类载入器查找servlet类的目录称作仓库(repository)
        loader=new URLClassLoader(urls);
        } catch (IOException e) {
            e.printStackTrace();
        }

        Class myclass=null;

        try {
            System.out.println("需要载入的 servletName:"+servletName);
            myclass=loader.loadClass(servletName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Servlet servlet=null;
        try {
            servlet=(Servlet) myclass.newInstance();
            servlet.service(req, res);
        }  catch (Exception e) {
            e.printStackTrace();
        }

    }
}

6 . 需要注意的两点:

1)第一点需要注意的:在ServletProcessor类的process(Request req,Response res)中如下写是不好的,因为在service(ServletRequest req, ServletResponse res)方法中,可以将req下转型为Request型,从而req可以访问parse方法,可以将res下转型为Request型,从而res可以访问sendStaticResource()方法:

    servlet=(Servlet) myclass.newInstance();
            servlet.service(req, res);

2)针对上一点的改进方法,增加ResponseFacade类如下图:
这里写图片描述

3)将上1)步的代码改为如下,为什么这样能避免不好的情况,在下一篇文章中举例说明:

            servlet=(Servlet) myclass.newInstance();
            RequestFacade requestFacade=new RequestFacade(req);
            ResponseFacade responseFacade=new ResponseFacade(res);
            servlet.service(requestFacade, responseFacade);

4)第2个需要注意的问题,如下图,ServletResponse为接口,3)中servlet.service(requestFacade, responseFacade)会调用被访问servletName类的service(ServletRequest req, ServletResponse res)方法,例如尽管res是ServletResponse 实例,当使用res.getWriter(),实际上调用的是Response类中重写的getWriter():
这里写图片描述

深入剖析Tomcat(中文版+英文版)》.rar 《深入剖析Tomcat深入剖析Tomcat 4和Tomcat 5中的每个组件(如果TOMCAT版本有点老,不过现在的Tomcat6和7同样可以借鉴参考),并揭示其内部工作原理。通过学习《深入剖析Tomcat》,你将可以自行开发Tomcat组件,或者扩展已有的组件。 Tomcat是目前比较流行的Web服务器之一。作为一个开源和小型的轻量级应用服务器,Tomcat 易于使用,便于部署,但Tomcat本身是一个非常复杂的系统,包含了很多功能模块。这些功能模块构成了Tomcat的核心结构。《深入剖析Tomcat》从最基本的HTTP请求开始,直至使用JMX技术管理Tomcat中的应用程序,逐一剖析Tomcat的基本功能模块,并配以示例代码,使读者可以逐步实现自己的Web服务器。 目录 第1章 一个简单的web服务器 1.1 http 1.1.1 http请求 1.1.2 http响应 1.2 socket类 1.3 应用程序 1.3.1 httpserver类 1.3.2 request类 1.3.3 response类 1.3.4 运行应用程序 1.4 小结 第2章 一个简单servlet容器 2.1 javax.servlet.servlet接口 2.2 应用程序 2.2.1 httpserver1类 2.2.2 request类 2.2.3 response类 2.2.4 staticresourceprocessor类 2.2.5 servletprocessor1类 2.2.6 运行应用程序 2.3 应用程序 2.4 小结 第3章 连接器 3.1 stringmanager类 3.2 应用程序 3.2.1 启动应用程序 3.2.2 httpconnector类 3.2.3 创建httprequest对象 3.2.4 创建httpresponse对象 3.2.5 静态资源处理器和servlet处理器 3.2.6 运行应用程序 3.3 小结 第4章 tomcat的默认连接器 4.1 http 1.1的新特性 4.1.1 持久连接 4.1.2 块编码 4.1.3 状态码100的使用 4.2 connector接口 4.3 httpconnector类 4.3.1 创建服务器套接字 4.3.2 维护httpprocessor实例 4.3.3 提供http请求服务 4.4 httpprocessor类 4.5 request对象 4.6 response对象 4.7 处理请求 4.7.1 解析连接 4.7.2 解析请求 4.7.3 解析请求头 4.8 简单的container应用程序 4.9 小结 第5章 servlet容器 5.1 container接口 5.2 管道任务 5.2.1 pipeline接口 5.2.2 valve接口 5.2.3 valvecontext接口 5.2.4 contained接口 5.3 wrapper接口 5.4 context接口 5.5 wrapper应用程序 5.5.1 ex05.pyrmont.core.simpleloader类 5.5.2 ex05.pyrmont.core.simplepipeline类 5.5.3 ex05.pyrmont.core.simplewrapper类 5.5.4 ex05.pyrmont.core.simplewrappervalve类 5.5.5 ex05.pyrmont.valves.clientiploggervalve类 5.5.6 ex05.pyrmont.valves.headerloggervalve类 5.5.7 ex05.pyrmont.startup.bootstrap1 5.5.8 运行应用程序 5.6 context应用程序 5.6.1 ex05.pyrmont.core.simplecontextvalve类 5.6.2 ex05.pyrmont.core.simplecontextmapper类 5.6.3 ex05.pyrmont.core.simplecontext类 5.6.4 ex05.pyrmont.startup.bootstrap 5.6.5 运行应用程序 5.7 小结 第6章 生命周期 第7章 日志记录器 第8章 载入器 第9章 session管理 第10章 安全性 第11章 standardwrapper 第12章 standardcontext类 第13章 host和engine 第14章 服务器组件和服务组件 第15章 digester库 第16章 关闭钩子 第17章 启动tomcat 第18章 部署器 第19章 manager应用程序的servlet
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值