zoukankan      html  css  js  c++  java
  • Servlet学习笔记【1】--- 背景和基础知识(CGI、Web服务器发展史、Servlet简介、任务、继承结构)

    本文主要讲Servlet的基础知识和背景知识。

    1 CGI简介

    CGI(Common Gateway Interface 公共网关接口)是WWW技术中最重要的技术之一,有着不可替代的重要地位。CGI是外部应用程序(CGI程序)与WEB服务器之间的接口标准,是在CGI程序和Web服务器之间传递信息的过程。CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静态超媒体文档变成一个完整的新的交互式媒体。

    Common Gateway Interface,简称CGI。在物理上是一段程序,运行在服务器上,提供同客户端HTML页面的接口。这样说大概还不好理解。那么我们看一个实际例子:现在的个人主页上大部分都有一个留言本。留言本的工作是这样的:先由用户在客户端输入一些信息,如评论之类的东西。接着用户按一下“发布或提交”(到目前为止工作都在客户端),浏览器把这些信息传送到服务器的CGI目录下特定的CGI程序中,于是CGI程序在服务器上按照预定的方法进行处理。在本例中就是把用户提交的信息存入指定的文件中。然后CGI程序将执行结果返回给服务器(webServer),然后服务器将结果返回给客户端,表示请求的任务已经结束。此时用户在浏览器里将看到“留言结束”的字样,整个过程结束。

    2 Web服务器发展历史

    通过服务器可以访问静态资源和动态资源。

    静态资源就是一些图片、视频等文件。访问流程:读取磁盘文件到内存中--->启动IO流-->将文件内容以字符串形式返回给浏览器。

    动态资源是一些代码,需要执行后将结果返回给浏览器端。而要在本地执行对应的代码,就需要有执行环境和标准接口规范(个人理解就是上边的CGI)。

    1)早期CGI模式服务器

    CGI模式的特点:是将服务端的动态资源基于进程(process)方法来运行。由于进程的执行非常耗费时间,且内存空间浪费,所以效率极其低下。

    2)FastCGI模式服务器

    所谓的fastCGI的模式其实就是当前的CGI模式中添加的一个pooling(资源池)的概念,在服务器启动时初始化固定的进程来提高处理客服端的请求的速度,但是该方法治标不治本。

    3)Servlet模式服务器

    技术特点:

    与传统的CGI模式不同,Servlet运行模式改为单进程多线程的模式(线程程运行在进程中)。

    单进程:服务器;

    多线程:服务端的Servlet。

    这样就大大提高了运行效率。

    3 Servlet简介

    Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

    使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

    Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。但是相比于 CGI,Servlet 有以下几点优势:

    • 性能明显更好。
    • Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
    • Servlet 是独立于平台的,因为它们是用 Java 编写的。
    • 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
    • Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。

    4 Servlet架构

    下图显示了 Servlet 在 Web 应用程序中的位置。

    5 Servlet任务

    Servlet 执行以下主要任务:

    • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
    • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
    • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
    • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
    • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

    6 Servlet的继承结构

    在Tomcat项目包中,有个lib目录,下边有个servlet-api.jar文件包,该jar包就是Tomcat对Servlet的接口实现。通过解压和反编译后,可以查看里边的实现代码。

    解压方式:将jar包扩展名改为rar,然后解压。

    反编译方式:通过jd-gui.exe反编译工具实现将class文件反编译为可读的java代码文件。

    通过上边解压和反编译,在servlet-apijavaxservlet文件夹下,我们可以看到Servlet.class,其反编译后代码如下:

     1 package javax.servlet;
     2 
     3 import java.io.IOException;
     4 
     5 public abstract interface Servlet
     6 {
     7   public abstract void init(ServletConfig paramServletConfig)
     8     throws ServletException;
     9 
    10   public abstract ServletConfig getServletConfig();
    11 
    12   public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
    13     throws ServletException, IOException;
    14 
    15   public abstract String getServletInfo();
    16 
    17   public abstract void destroy();
    18 }

    GenericServlet.class反编译后代码如下:

     1 package javax.servlet;
     2 
     3 import java.io.IOException;
     4 import java.io.Serializable;
     5 import java.util.Enumeration;
     6 
     7 public abstract class GenericServlet
     8   implements Servlet, ServletConfig, Serializable
     9 {
    10   private static final long serialVersionUID = 1L;
    11   private transient ServletConfig config;
    12 
    13   public void destroy()
    14   {
    15   }
    16 
    17   public String getInitParameter(String name)
    18   {
    19     return getServletConfig().getInitParameter(name);
    20   }
    21 
    22   public Enumeration<String> getInitParameterNames()
    23   {
    24     return getServletConfig().getInitParameterNames();
    25   }
    26 
    27   public ServletConfig getServletConfig()
    28   {
    29     return this.config;
    30   }
    31 
    32   public ServletContext getServletContext()
    33   {
    34     return getServletConfig().getServletContext();
    35   }
    36 
    37   public String getServletInfo()
    38   {
    39     return "";
    40   }
    41 
    42   public void init(ServletConfig config)
    43     throws ServletException
    44   {
    45     this.config = config;
    46     init();
    47   }
    48 
    49   public void init()
    50     throws ServletException
    51   {
    52   }
    53 
    54   public void log(String msg)
    55   {
    56     getServletContext().log(getServletName() + ": " + msg);
    57   }
    58 
    59   public void log(String message, Throwable t)
    60   {
    61     getServletContext().log(getServletName() + ": " + message, t);
    62   }
    63 
    64   public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
    65     throws ServletException, IOException;
    66 
    67   public String getServletName()
    68   {
    69     return this.config.getServletName();
    70   }
    71 }

    在servlet-apijavaxservlethttp文件夹下,可以找到HttpServlet.class文件,反编译后内容如下:

     1 package javax.servlet.http;
     2 
     3 // ...省略代码
     4 import javax.servlet.GenericServlet;
     5 
     6 public abstract class HttpServlet extends GenericServlet
     7 {
     8   // ...省略代码
     9   
    10   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    11     throws ServletException, IOException
    12   {
    13     // ...省略实现代码
    14   }
    15 
    16   protected long getLastModified(HttpServletRequest req)
    17   {
    18     return -1L;
    19   }
    20 
    21   protected void doHead(HttpServletRequest req, HttpServletResponse resp)
    22     throws ServletException, IOException
    23   {
    24     // ...省略实现代码
    25   }
    26 
    27   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    28     throws ServletException, IOException
    29   {
    30     // ...省略实现代码
    31   }
    32 
    33   protected void doPut(HttpServletRequest req, HttpServletResponse resp)
    34     throws ServletException, IOException
    35   {
    36     // ...省略实现代码
    37   }
    38 
    39   protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
    40     throws ServletException, IOException
    41   {
    42     // ...省略实现代码
    43   }
    44 
    45   private static Method[] getAllDeclaredMethods(Class<?> c)
    46   {
    47     // ...省略实现代码
    48   }
    49 
    50   protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
    51     throws ServletException, IOException
    52   {
    53     Method[] methods = getAllDeclaredMethods(super.getClass());
    54     // ...省略实现代码
    55   }
    56 
    57   protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
    58     throws ServletException, IOException
    59   {
    60     String CRLF = "
    ";
    61     StringBuilder buffer = new StringBuilder("TRACE ").append(req.getRequestURI()).append(" ").append(req.getProtocol());
    62     // ...省略实现代码
    63   }
    64 
    65   protected void service(HttpServletRequest req, HttpServletResponse resp)
    66     throws ServletException, IOException
    67   {
    68     String method = req.getMethod();
    69     long lastModified;
    70     // ...省略实现代码
    71   }
    72 
    73   private void maybeSetLastModified(HttpServletResponse resp, long lastModified)
    74   {
    75     if (resp.containsHeader("Last-Modified"))
    76       return;
    77     if (lastModified >= 0L)
    78       resp.setDateHeader("Last-Modified", lastModified);
    79   }
    80 
    81   public void service(ServletRequest req, ServletResponse res)
    82     throws ServletException, IOException
    83   {
    84     // ...省略实现代码
    85   }
    86 }

    从上边源码中可以发现:

    servlet.class文件就是实现SUN公司JavaEE制定的Servlet标准接口的代码;

    GenericServlet.class 中间层 抽象类 直接实现Servlet,并没有将Servlet所有方法实现,添加了一些自己的方法;

    http目录下的HttpServlet继承了GenericServlet,该主要实现与http协议相关的接口(doPost、doGet、doPut、doDelete)。

    GenericServlet存在的原因:解除http协议和Servlet之间的耦合。随着技术发展后续可能会替换http,改为其它协议。这样如果要切换,可复用的部分在GenericServlet中,并不需要重新开发,只需要将httpServlet基于新协议重新开发即可。这就是开闭原则,需要更改时,只需要修改一部分代码即可。

    Servlet是基于Http协议的。

    参考资料&内容来源:

    百度百科:https://baike.baidu.com/item/CGI/607810?fr=aladdin&fromid=6717913&fromtitle=%EF%BC%A3%EF%BC%A7%EF%BC%A9

    速学堂:http://www.sxt.cn/tomcat/1-1-1.html

    菜鸟教程:http://www.runoob.com/servlet/servlet-intro.html

  • 相关阅读:
    关于 锁的四种状态与锁升级过程 图文详解
    悲观锁与乐观锁的实现(详情图解)
    面试三轮我倒在了一道sql题上——sql性能优化
    我的程序跑了60多小时,就是为了让你看一眼JDK的BUG导致的内存泄漏。
    快来!我从源码中学习到了一招Dubbo的骚操作!
    我从LongAdder中窥探到了高并发的秘籍,上面只写了两个字...
    震惊!ConcurrentHashMap里面也有死循环,作者留下的“彩蛋”了解一下?
    mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比,于是写了个插件。
    吐血输出:2万字长文带你细细盘点五种负载均衡策略。
    mybatis开发,你用 xml 还是注解?我 pick ...
  • 原文地址:https://www.cnblogs.com/zhaoweikai/p/9877222.html
Copyright © 2011-2022 走看看