首页 > 其他 > 详细

03-Servlet

时间:2020-07-28 11:08:04      阅读:69      评论:0      收藏:0      [点我收藏+]

Servlet 简介

Sun提供的一种动态web资源开发技术。本质上一段Java程序。将Servlet加入到Servlet容器中运行。

区分以下几个名词:

  • Servlet:属于 JavaEE 重要技术规范,构建了 "接收请求→调用Servlet程序处理→返回响应"基本模型
  • Servlet 程序: Java提供了开发Servlet程序的API,该API可以说是Servlet容器的一部分,它对接应用程序和Servlet容器
  • Servlet 容器:实现了Servlet技术规范的部署环境,它可以部署运行Servlet程序
  • JavaWEB 容器
    • Web容器:能够部署多个WEB应用程序的环境
    • JavaWEB 容器实现了 JavaEE 规定的 WEB 应用技术规范(Servlet、JSP、Java Web Socket)的部署环境
    • 完整的 JavaWeb 容器包含 Servlet 容器

手写一个 Servlet

  1. 写一个类实现 Servlet<I>
    技术分享图片
  2. 将写好的类配置到 tomcat 下 web应用的 web.xml 中,配置对外访问路径(虚拟路径)
    技术分享图片

一次请求响应过程

技术分享图片
技术分享图片

步骤

  • 分析出当前请求的是哪台虚拟主机
    • 查看"Host"请求头,分析出访问的是哪台虚拟主机
      技术分享图片
    • 如果没有"Host"请求头(访问时直接敲的IP地址),则会去找缺省虚拟主机
      技术分享图片
  • 分析当前请求访问的是当前虚拟主机中的哪个Web资源
    技术分享图片
    • 从请求行中请求的资源部分中分析出当前访问的是哪个 web 应用
    • 分析当前请求要访问的是这个 web 应用中的哪个资源
  • Sever查找该web应用的 web.xml 文件,查看有没有对应的虚拟路径
    • 如果有,则用这个虚拟路径对应的资源作响应
      技术分享图片
    • 没有,404

Servlet相关工作

  • Sever 首先检查是否已经装载并创建了该 Servlet 的实例
    • Servlet 在第一次被访问到的时候,Sever 创建出该 Servlet 的一个实例对象
    • 创建出对象后,立即调用 init() 做初始化操作
    • 创建出来的对象会一直驻留在内存中,为后续对这个 Servlet 的访问服务
  • Servlet 容器创建本次 HTTP 请求相关的对象,即:
    • 封装HTTP请求消息的 HttpServletRequest 对象
    • 一个代表HTTP响应消息的 HttpServletResponse 对象
  • 调用Servlet的 service() 并将请求和响应对象作为参数传递进去,每次对这个Servlet的访问都会导致Servlet中 service() 执行
  • 当web应用被移除出容器或Sever被关闭,随着web应用的销毁,Servlet 会被销毁,但在销毁之前,Sever会调用Servlet的 destory() 做一些善后工作
  • Sever 从 response 对象中获取出之前写入的数据,组织成 HTTP 响应消息打给 browser

流程图

技术分享图片

Servlet 继承结构

  • Servlet<I>:定义了Servlet应该具有的基本方法
  • GenericServlet <abstract C>:通用的基本Servlet实现
    • 对于不常用的方法,在这个实现类中进行了基本的实现
    • 对于 service() 则保留为抽象方法,需要让子类去实现
  • HttpServlet<C>
    • 在GenericServlet的基础上基于HTTP协议进行了进一步强化,即实现了 service():根据当前请求方式,调用对应的 doXXX()
      技术分享图片
    • 在实际开发Servlet中,只需继承 HttpServlet,覆盖具体要处理的doXXX方法,就可以实现"根据不同的请求方式实现不同的处理"

Tips

Servlet 映射

  • 一个 <servlet> 可以对应多个 <servlet-mapping>,从而使一个Servlet可以有多个路径来访问
  • <url-pattern>中的路径可以使用 * 匹配符进行匹配
    • 规范:① 得以 / 开头 ,/* "结尾 ② *.后缀
  • 由于 * 的引入,有可能一个路径被多个 <url-pattern> 匹配,这时优先级判断条件
    • 哪个 <url-pattern> 最长匹配 选哪个
    • *.后缀 优先级最低,比 /* 还低
    • 举例
      技术分享图片
  • 注意,[路径] 和 [扩展名] 匹配无法同时设置,比如下面的几个 <url-pattern> 都是非法的,如果设置,tomcat 将报错
    <url-pattern>/kata/*.jsp</url-pattern>
    <url-pattern>/*.jsp</url-pattern>
    <url-pattern>he*.jsp</url-pattern>
    
  • 关于 /*
    the /* on a servlet overrides all other servlets, including all servlets provided by the servletcontainer such as the default servlet and the JSP servlet. Whatever request you fire, it will end up in that servlet. This is thus a bad URL pattern for servlets.
  • <servlet> 配置 <load-on-startup> 标签
    • 概述
      • 配置该元素可以使得在 web 应用启动时,一并装载和创建该 Servlet 的实例对象,以及调用 Servlet 实例对象的 init()
      • 该标签的标签体是一个 int 类型的数值,如果有多个配置该元素的 Servlet,可根据数值大小,来确定启动顺序
    • 用途:为 web 应用写一个 InitServlet,这个 Servlet 配置为启动时装载,为整个web应用创建必要的数据库表和数据

缺省 Servlet

  • 如果有一个Servlet的 <url-pattern> 被配置为 /,这个 Servlet 就变成了缺省 Servlet
  • 其他 Servlet 都不处理的请求,由缺省Servlet来处理,也就是 "请求资源部份的名称" 对不上任一 <url-pattern>,比如 html、css、js…
  • 对静态资源的访问、404、500 页面… ,都是由缺省Servlet来处理的
  • 通常不会自己去配置缺省Servlet,tomcat/config/web.xml 中给配过了
    技术分享图片

线程安全问题

  • 起源:当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的 service(),因此 service() 内如果访问了同一个资源的话,就有可能引发线程安全问题
  • 解决方案1:实现 SingleThreadModel<I>
    • 如果某个Servlet实现了 SingleThreadModel<I>,那么Servlet引擎将以单线程模式来调用 service()SingleThreadModel <I> 没有任何方法,只是一个"标记接口"。在Sever内部维护一个"池",产生多个 Servlet 实例对象,并发的每个线程分别调用一个独立的 Servlet 实例对象。
    • 实现 SingleThreadModel <I> 并不能真正解决 Servlet 的线程安全问题,因为 Servlet 引擎会创建多个 Servlet 实例对象,而真正意义上解决多线程安全问题是指一个 Servlet 实例对象被多个线程同时调用的问题。事实上,在 Servlet API 2.4 中,已经将 SingleThreadModel <I> 标记为Deprecated(过时的)。
  • 解决方法2:加锁
    • 效率低下。故尽量少使用类变量,如果必须使用类变量,就要加锁,代码中尽量只包住有线程问题的代码,让锁的时间尽量的短,减少等待时间,提高响应速度

ServletConfig

  • 代表当前 Servlet 在 web.xml 中的配置信息。
    技术分享图片
  • 如何获得 ServletConfig
    技术分享图片
  • ServletConfig 常用方法
    技术分享图片
  • 代码演示
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        ServletConfig config = this.getServletConfig();
        
        // 获取当前Servlet在web.xml中配置的名称
        String sName = config.getServletName();
        System.out.println(sName);
        
        // 获取当前Servlet在web.xml中配置的初始化参数name1
        String value1 = config.getInitParameter("name1");
        System.out.println(value1);
        
        // 获取所有初始化参数
        Enumeration<String> enums = config.getInitParameterNames();
        while(enums.hasMoreElements()) {
            String name = enums.nextElement();
            String value = config.getInitParameter(name);
            System.out.println(name + ":" + value);
        }
    }
    

ServletContext

概述

  • WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的 ServletContext 对象,它代表当前web应用
  • ServletConfig 对象中维护了 ServletContext 对象的引用,开发人员在编写servlet时,可以通过ServletConfig的 getServletContext()获得 ServletContext 对象。
    技术分享图片
  • 作用范围:整个web应用范围内共享数据

功能

  • 作为"域对象"可以在整个web应用范围内共享数据
    • 域对象
      • 作用范围:整个web应用范围内共享数据
      • 生命周期:server启动,web加载后创建出ServletContext对象后,域产生;当web应用被移除出容器或server关闭,随着web应用的销毁,域销毁
    • 常用方法
      public void setAttribute(String name, Object object)
      public Object getAttribute(String name)
      public void removeAttribute(String name)
      
  • 获得web应用的初始化参数
    • web应用的初始化参数
      技术分享图片
    • 常用方法
      String getInitParameter(String name)
      Enumeration<String> getInitParameterNames()
      
    • 附:搞清楚"请求参数"、"初始化参数"、"域属性"的区别
      • 请求参数(parameter):browser 发送过来的请求中的参数信息
      • 初始化参数(InitParameter):在web.xml中为 Servlet 或 ServletContext 配置的初始化时带有的基本参数
      • 域属性(attribute):四大作用域中存取的键值对
  • 实现 Servlet 的转发
    • 请求转发和请求重定向
      • 请求重定向(302+Location):两次请求,两次响应
      • 请求转发(server内部进行资源流转):一次请求,一次响应
    • 代码演示
      // 虚拟路径
      String path = "/servlet/SContextServlet3";
      RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(path);
      dispatcher.forward(request, response);
      
  • 加载资源文件
    • 在Servlet中读取资源文件时,遇到的问题
      • 如果写相对路径,路径会相对于程序启动目录:JavaProject → workspace/project_name;Web Project → tomcat/bin
      • 如果写硬盘路径,可以找到资源。但是可移植性差
    • 为了解决这样的问题,ServletContext提供了方法:public String getRealPath(String)
    • 代码演示
      public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
          // File file = new File("config.properties");
          // 当前程序启动的目录下找文件 => D:\Java\tomcat\bin\config.properties
          // System.out.println(file.getAbsolutePath());
      
          // 方法底层会拼接 [当前web应用在虚拟主机管理的文件夹的
          // 硬盘路径] 在方法形参前面从而获得当前资源的硬盘路径
          String path = getServletContext().getRealPath("config.properties");
          System.out.println(path);
      }
      
    • 补充:在非Servlet环境下,可以采用 [类加载器] 的方式读取资源。类加载器从哪里加载类,就从哪里加载资源文件,即 webapps/[project_name]/WEB-INF/classes,web项目的类加载目录
      技术分享图片
      public void method() {
          // 类加载器从哪里加载类, 就从哪里加载资源文件, 对应到web应用, 也就是classes文件夹
          File file = new File(PathDemo.class.getClassLoader()
                                      .getResource("config2.properties").getPath());
          System.out.println(file.getAbsolutePath());
      }
      

03-Servlet

原文:https://www.cnblogs.com/liujiaqi1101/p/13388401.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!