• 一个简单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类的实例向上转型就不会出现问题了。

      • 运行结果如下:

      • 结果

      • 结果

  • 相关阅读:
    教你用photoshop cs5或者cs6做IPad,背景随意换,gif制作,高清教程,原创
    ASP.NET MVC4 IN ACTION学习笔记第一波
    潜移默化学会C#不常用语法《1》动态类型绑定dynamic
    SubSnoic 框架入门到提高(1)全程记录
    杨洋疯狂C# 刊号:201208 第1期ASPNET验证(一)
    杨洋疯狂C# 刊号:201207 第1期
    ASP.NET MVC4 IN ACTION学习笔记第二波
    JavaScript深入【表达式和运算符(上集)】你能过我8关js运算符的题目吗?
    清新空气我的.net(C#)生涯知识总结 跨CSS,JS,JAVA,AJAX,WPF,WCF,LINQ,ASP.NET,Winform,Sqlserver,Mysql,EF,OOP,开发工具等
    潜移默化学会WPF(Treeview异步加载节点)
  • 原文地址:https://www.cnblogs.com/Black-Cobra/p/8901497.html
Copyright © 2020-2023  润新知