从零开始写一个Tomcat(贰)--建立动态服务器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始写一个Tomcat(贰)--建立动态服务器相关的知识,希望对你有一定的参考价值。

    上文书说道如何通过http协议建立一个静态的服务器来访问静态网页,但我们选择tomcat最主要的原因还是因为它能动态的执行servlet,这边文章将引导你实现一个能够运行servlet的服务器,这个简易的服务器符合tomcat的基本原理,但真的tomcat远不是这么简单,即使是15年前的tomcat4。

   1.主程序逻辑分离

    既然要实现动态的服务器,首先我们要实现模式的识别,在tomcat中,tomcat通过读取web.xml,在servlet的配置中通过url的模式来匹配servlet,我们这里当然不会这么复杂,我们暂且设置如下规则,如果你想访问一个servlet,那么你就在浏览器输入如localhost/servlet/TestServlet这样的地址,TestServlet是你servlet的名字,准确点来说就是你的servlet编译后的class的名称,当然你可以起你任意喜欢的名字

    以上文为基础,将main方法中的静态处理改成如下

 if(request.getUri().startsWith("/servlet/"))
{
       ServletProcessor processor=new ServletProcessor();
        processor.process(request,response);
}else{
        StaticResponseProcessor processor=new StaticResponseProcessor();
         processor.process(request,response);
}

    当request获得的uri以servlet开头,就去访问ServletProccess的方法.

    2.ServletProccess

    这个类的职责就是用于找到servlet并调用.不多说,先上代码

    public class ServletProcessor {
    public void process(Request request,Response response)
    {
        String uri=request.getUri();
        String servletName=uri.substring(uri.lastIndexOf("/")+1);
        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(repository);
            urls[0] = new URL(null,repository,streamHandler);
            loader=new URLClassLoader(urls);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Class myClass=null;
        try{
            myClass=loader.loadClass(servletName);
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
        Servlet servlet=null;

        try{
            servlet=(Servlet)myClass.newInstance();
            servlet.service(request,response);

        }catch (Exception e){
            System.out.println(e.toString());
        }catch (Throwable t){
            System.out.println(t.toString());
        }

    }
}

     首先,我们要找到这个类,这个类应该在哪呢,在tomcat中,这个类即class文件在/WEB-INF/classes下,我们暂且先直接放在webroot下面,负责记录存储位置的是一个专门的Constants类的静态变量

 public static final String WEB_ROOT=System.getProperty("user.dir")+File.separator+"webroot";

  程序使用一个URLClassLoader来加载这个class,为了禁止servlet访问tomcat中的类,tomcat自定义了一个加载器,这个问题以后再详细说明,加载完类之后,用newInstance实例化,按理说这里会先调用init方法,老规矩,先忽略了,然后调用servlet的service方法,这时候细心的你可能发现了,在servlet的方法中,我的request是实现了servletRequest接口的,同理还有response,但你的request是自己定义的,这么调用肯定是错的,而且说好的response.getWriter呢,下面我们来改造request和response

    3.request,response

    其实并不需要多少操作,只需要把request实现ServletRequest接口,response实现ServletResponse接口,然后使用IDE的代码补全,里面的方法先都空着好了,在response的getWriter添加如下代码

 public PrintWriter getWriter() throws IOException {
        writer=new PrintWriter(output,true);
        return writer;
    }

 

    4.facade

    至此,这个动态服务器已经可以用了,但是不知道你有没有注意到另一个问题,我们在servlet使用的request是tomcat传给我们的,那也就是说我们可以把这个servletRequest向下转型为tomcat的request类,然后我们就可以访问request的parse()之类的方法,但显然tomcat是不容许的,tomcat在这里使用了外观模式新建一个类requestFacade,在构造函数中传入tomcat的request,实现所有外部能够访问的方法,在方法中调用request的相应的方法,这样就能完美的隐藏那些request的必须的且不应该被servlet访问的public方法.

 

 

    5.结果

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("service");
res.getWriter().println("service");
}


技术分享



地址:https://github.com/Asens/AsServer/tree/master/AsServerV1.0.1

下集预告:我会把接受请求和处理请求的逻辑分离,并引入线程池概念,是这个服务器能够同时处理多个请求

    

 

    

以上是关于从零开始写一个Tomcat(贰)--建立动态服务器的主要内容,如果未能解决你的问题,请参考以下文章

[转]从零开始山寨Caffe·贰:主存模型

从零开始写一个迷你版的Tomcat

教你从零开始写一个迷你版的Tomcat!

从零开始写JavaWeb框架(第一章节)

[从零开始搭网站六]为域名申请免费SSL证书(https),并为Tomcat配置https域名所用的多SSL证书

从零开始建立一个属于你个人的Hexo博客