一个简单servlet容器

一个简单servlet容器

2.1 javax.servlet.Servlet接口

  • Servlet编程需要使用javax.servlet和javax.servlet.http两个包下的接口和类
  • 在所有的类中javax.servlet.Servlet接口是最重要的。所有的servlet程序都必须实现该接口或继承实现了该接口的类
  • tomcat8中该接口如下:
  • package javax.servlet;
    import java.io.IOException;
    public interface Servlet {
        public void init(ServletConfig config) throws ServletException;
        public ServletConfig getServletConfig();
        public void service(ServletRequest req, ServletResponse res)
                throws ServletException, IOException;
        public String getServletInfo();
        public void destroy();
    }
  • 在Servlet接口中,init()、service()和destroy()方法是和servlet生命周期相关的方法。当实例化某个servlet类后,servlet容器就会调用其init()方法进行初始化。servlet容器只会调用该方法一次,调用后则可以执行service()方法了。
  • 在servlet接收任何请求之前,必须是经过初始化的。该方法可以进行覆盖,自定义初始化。
  • 当servlet的一个客户端请求到达后,servlet容器就调用相应的servlet的service方法,并将 javax.servlet.ServletRequest对象和javax.servlet.ServletResponse对象作为参数传入。
  • ServletRequest对象包含客户端的HTTP请求信息,ServletResponse对象则封装servlet的响应信息。
  • 在整个servlet周期内,service会被多次调用。
  • 在将servlet容器从服务中移除之前,servlet容器会调用servlet实例的destory方法。
  • 使用PrimitiveServlet来测试servlet容器应用程序
    • import javax.servlet.*;
      import java.io.IOException;
      import java.io.PrintWriter;
      
      public class PrimitiveServlet implements Servlet {
      
          public void init(ServletConfig config) throws ServletException {
              System.out.println("init");
          }
      
          public void service(ServletRequest request, ServletResponse response)
              throws ServletException, IOException {
              System.out.println("from service");
              PrintWriter out = response.getWriter();
              out.println("Hello. Roses are red.");
              out.print("Violets are blue.");
          }
      
          public void destroy() {
              System.out.println("destroy");
          }
      
          public String getServletInfo() {
              return null;
          }
          public ServletConfig getServletConfig() {
              return null;
          }
      }

      2.2应用程序1

  • 对一个Servlet的每个HTTP请求,一个功能齐全的servlet容器需要做到以下几点:
    • 当第一次调用某个servlet时,要载入该servlet类,并调用其init方法
    • 针对每一个request请求,创建一个javax.servlet.ServletRequest实例和一个javax.servlet.ServletResponse实例
    • 调用该servlet的service方法,将ServletRequest对象和ServletResponse对象作为参数传入
    • 当关闭servlet类时,调用destory方法
  • 接下来建立一个Servlet容器,功能如下:
    • 等待HTTP请求
    • 创建一个ServletRequest对象和一个ServletResponse对象
    • 若请求静态资源,则调用StaticResourceProcessor对象的process方法,传入上面的两个对象
    • 若请求servlet,则载入相应的servlet类,调用其service方法。
    • 类关系UML图如下:
    • 基于Java的Servlet容器实现,需要调用Java提供的有关接口,比如javax.servlet.ServletRequest和javax.servlet.ServletResponse。
    • 任何一个Servlet都需要实现Servlet接口或者继承实现该接口的类。
    • 具体的请求过程以及类型如图:
  • 代码示例:
    • if (request.getUri().startsWith("/servlet/")) {
        ServletProcessor1 processor = new ServletProcessor1();
        processor.process(request, response);
      }
      else {
        StaticResourceProcessor processor = new StaticResourceProcessor();
        processor.process(request, response);
      }
    • 在上面代码中可以看出对于静态资源使用StaticResourceProcessor容器,对于动态Servlet资源使用ServletProcessor1容器
    • package ex02.pyrmont;
      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
                  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
                  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 class.
                  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());
              }
      
          }
      }
    • 上面代码通过newInstance创建了一个Servlet的实例,并调用了service方法,并传入参数request和response。但是该参数是向上转型的。
    • 这通常是不安全的,因为外部人员可以将其向下转型为Request的对象,就可以调用其方法.解决方法是创建Request和Response的外观类(外观类和原类实现同一个接口,在外观类中创建私有接口对象用原类进行赋值即可)。而在调用接口对象时使用外观类就不会导致原类的方法泄露
    • 示例如下:
    • package ex02.pyrmont;
      public class RequestFacade implements ServletRequest {
      
          private ServletRequest request = null;
      
          public RequestFacade(Request request) {
              this.request = request;
          }
      
      /* implementation of the ServletRequest*/
      ...
      }
      package ex02.pyrmont;
      
      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 the ServletRequest*/
      }
    • 这样在上面service方法中使用RequestFacade类的实例向上转型就不会出现问题了。
    • 运行结果如下:

原文地址:https://www.cnblogs.com/Black-Cobra/p/8901497.html

时间: 2024-11-03 00:31:08

一个简单servlet容器的相关文章

【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八)

目录 [SSH进阶之路]一步步重构容器实现Spring框架--从一个简单的容器开始(八) [SSH进阶之路]一步步重构容器实现Spring框架--解决容器对组件的"侵入式"管理的两种方案--主动查找和控制反转(九)(未更新) [SSH进阶之路]一步步重构容器实现Spring框架--配置文件+反射实现IoC容器(十)(未更新) [SSH进阶之路]一步步重构容器实现Spring框架--彻底封装,实现简单灵活的Spring框架(十一)(未更新) 最近一直在和容器打交道,甚至前面的博文,我们也

写一个简单的servlet

昨天写完hibernate的小demo后,想写一个简单structs2,但是发现好像自己连servlet都忘了怎么写了,所以一切从头开始,先写一个简单servlet把 第一步 肯定是建立项目了,打开自己eclipse(myeclipse,sts,idea).然后file->new->java project.这里肯定会有疑问,为啥不建立一个web project呢.呃,原因很简单,因为要从头来,一切都从头来呗,web project里 web方面的属性都给配置好了,就起不到学习的作用了. 名字

从零构建一个简单的 Python Web框架

为什么你想要自己构建一个 web 框架呢?我想,原因有以下几点: 你有一个新奇的想法,觉得将会取代其他的框架 你想要获得一些名气 你遇到的问题很独特,以至于现有的框架不太合适 你对 web 框架是如何工作的很感兴趣,因为你想要成为一位更好的 web 开发者. 接下来的笔墨将着重于最后一点.这篇文章旨在通过对设计和实现过程一步一步的阐述告诉读者,我在完成一个小型的服务器和框架之后学到了什么.你可以在这个代码仓库中找到这个项目的完整代码. 我希望这篇文章可以鼓励更多的人来尝试,因为这确实很有趣.它让

how tomcat works 读书笔记(二)----------一个简单的servlet容器

app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/article/details/39378157) 回顾我们上一章,我们开发了一个最最简单的web服务器,它可以使用户访问服务器内的静态资源.当然这是远远不够的,在这一节里,我们就试着让服务器在能相应静态资源的基础上继续支持servlet. servlet接口 javax.servlet.Servlet接口

一个简单的Servlet容器实现[一]

上篇写了一个简单的Java web服务器实现,只能处理一些静态资源的请求,本篇文章实现的Servlet容器基于前面的服务器做了个小改造,增加了Servlet请求的处理. 程序执行步骤 创建一个ServerSocket对象: 调用ServerSocket对象的accept方法,等待连接,连接成功会返回一个Socket对象,否则一直阻塞等待: 从Socket对象中获取InputStream和OutputStream字节流,这两个流分别对应request请求和response响应: 处理请求:读取In

2.一个简单的Servlet容器

很显然Http服务器会按照Http协议对获取的请求进行分析并返回规定的信息,通过对Http的理解,java大叔将其返回的信息封装成一个类,称为Servlet,至此,Http服务器在Java中就变成了按照Http协议对获取的请求进行分析并返Servlet,很明显,Http服务器在这里也就变为了Servlet容器...    注:服务器是什么?理解万岁...

Tomcat学习笔记(二)—— 一个简单的Servlet容器

1.简介:Servlet编程是通过javax.Servlet和javax.servlet.http这两个包的类和接口实现的,其中javax.servlet.Servlet接口至关重要,所有的Servlet必须实现该接口或者继承实现了该接口的类. 2.Servlet接口有5个方法: public void init(ServletConfig config) throws ServletException; public void service(ServletRequest request, S

深入剖析Tomcat-第二章:一个简单的servlet容器(2)

内容:在上一篇中存在一些安全问题,因为我们需要将request和response想上转型为ServletRequest和ServletResponse,了解这个servlet容器内部工作原理的servlet程序员可以将ServletRequest和ServletResponse分别向下转型然后就能调用Request和Response的parse()和sendStaticResource()了.所以我们需要利用外观类来解决,添加两个RequestFacade和ResponseFacade,然后分别

探秘Tomcat——一个简易的Servlet容器

即便再简陋的服务器也是服务器,今天就来循着书本的第二章来看看如何实现一个servlet容器. 背景知识 既然说到servlet容器这个名词,我们首先要了解它到底是什么. servlet 相比你或多或少有所了解.servlet是用java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容.狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者. 容器 容器的概念很大,在这里