Servlet & Servlet容器

作者: suxin1932 | 来源:发表于2019-08-04 17:31 被阅读0次

    1.Servlet

    servlet-4_0_FINAL下载地址
    https://download.oracle.com/otndocs/jcp/servlet-4-final-spec/index.html

    1.1简介

    Servlet是Server与Applet的缩写,是服务端小程序的意思。
    是SUN公司提供的一门用于开发动态Web资源的技术。
    
    Servlet本质上也是Java类,但要遵循Servlet规范进行编写,没有main()方法,
    它的创建、使用、销毁都由Servlet容器进行管理(如Tomcat)。
    
    Servlet是和HTTP协议是紧密联系的,其可以处理HTTP协议相关的所有内容。
    
    # web容器
    提供了Servlet功能的服务器,叫做Servlet容器,其常见容器有很多,如:
    Tomcat, Jetty, WebLogic Server, Glassfish, Websphere, JBoss等。
    

    1.2Servlet工作原理解析

    1.2.1一个HTTP请求的执行过程

    客户端发出请求'http://localhost:8080/xxx'
    
    根据Web.xml文件的配置,找到
    <url-pattern>对应的<servlet-mapping>
    读取<servlet-mapping>中<servlet-name>的值
    找到<servlet-name>对应的<servlet-class>
    找到该class并加载执行该class
    

    1.2.2Servlet的执行过程

    Servlet程序由Web服务器调用,当收到请求后,
    检查是否已装载并创建了该Servlet对象,如果没有则加载创建
    调用Servlet的init()方法初始化实例
    调用service()方法,处理请求并返回响应结果
    在服务器被停止或重启之前,调用destroy()方法释放资源
    

    1.2.3Servlet接口实现类

    SUN公司定义了两个实现类,GenerricServlet和HttpServlet,
    其中后者是前者的子类,它在原有基础上添加了一些HTTP协议处理方法,它比GenerricServlet功能更强大,
    所以我们一般将自己的类继承自HttpServlet,并重写doGet方法和doPost方法,不需要重写Service方法。
    

    1.2.4Servlet的一些细节

    1.2.4.1

    由于客户端是通过URL地址访问web服务器中的资源,
    所以Servlet程序弱项被外界访问,必须把Servlet程序映射到一个URL地址上,
    这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成
    (在Servlet3.0规范的特性中,该功能可以使用注解完成,不要求必须使用web.xml)。
    
    <servlet>元素用于注册Servlet,它包含两个主要的子元素:
    <servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的全限定名。
    
    <servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含两个子元素:
    <servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。
    

    1.2.4.2

    同一个Servlet可以被映射到多个URL上,
    即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
    
    在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:
    一种是“*.扩展名”。
    另一种是以(/)开头并以(/*)结尾。
    
    两个特点:
    >> 可以精确匹配,就用精确匹配,最后使用范围最宽泛的匹配
    >> /* 的优先级高于 *.扩展名 会先匹配
    

    1.2.4.3

    如果某个Servlet的映射路径只有一个(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
    
    凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,
    它们的请求访问都将交给缺省Servlet处理,
    也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
    
    在tomcat的安装目录/conf/web.xml中,注册了一个名称org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为缺省Servlet。
    
    当访问Tomcat服务器中的某个静态HTML文件或图片等资源时,实际上是在访问这个缺省Servlet。
    
    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
     
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
     
      <!--welcome pages-->
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
     
      <!--applicationContext.xml是全局的,应用于多个serverlet,配合listener一起使用-->
      <!-- 如果是监听多个文件,可用‘,’隔开 -->
     
      <context-param>
        <description>配置Spring配置文件路径</description>
        <param-name>contextConfigLocation</param-name>
     
        <param-value>classpath:spring/applicationContext.xml</param-value>
      </context-param>
     
      <!-- 定义SPRING监听器,加载spring -->
      <listener>
        <listener-class>
          org.springframework.web.context.request.RequestContextListener
        </listener-class>
      </listener>
     
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
     
      <!--log4j配置文件加载-->
      <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath:log4j.properties</param-value>
      </context-param>
      <!--启动一个watchdog线程每1800秒扫描一下log4j配置文件的变化-->
      <context-param>
        <param-name>log4jRefreshInterval</param-name>
        <param-value>1800000</param-value>
      </context-param>
      <context-param>
        <param-name/>
        <param-value/>
      </context-param>
     
      <!-- 配置Spring字符编码过滤器 -->
      <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
          <param-name>encoding</param-name>
          <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
          <param-name>forceEncoding</param-name>
          <param-value>true</param-value>
        </init-param>
      </filter>
      <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>
     
      <!-- Spring MVC 核心控制器 DispatcherServlet 配置开始 -->
      <!--配置springmvc DispatcherServlet-->
      <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <!--Sources标注的文件夹下需要新建一个spring文件夹-->
          <param-name>contextConfigLocation</param-name>
          <!-- 如果是监听多个文件,可用‘,’隔开 -->
          <param-value>classpath:spring/spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
      </servlet>
     
      <!-- 拦截设置 -->
      <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
        <url-pattern>/</url-pattern>
      </servlet-mapping>
      <!-- Spring MVC 核心配置结束 -->
     
      <!-- 激活Tomcat的defaultServlet来处理静态文件 -->
      <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/static/*</url-pattern>
      </servlet-mapping>
     
      <!-- session 时间 -->
      <session-config>
        <session-timeout>30</session-timeout>
      </session-config>
     
    </web-app>
    

    1.2.5Servlet的生命周期

    Servlet没有main()方法,不能独立运行,它的运行完全由Servlet引擎来控制和调度。
    
    针对客户端的多次Servlet请求,通常情况下,
    服务器只会在第一次请求的时候创建一个Servlet实例对象,并驻留在内存中,
    为后续的其他请求服务,直至web容器退出,Servlet实例对象才会销毁。
    
    在Servlet的整个生命周期内,Servlet的init()方法只被调用一次,
    而对于每一个请求都会调用一次Servlet的service()方法service根据请求方式调用doGet或doPost方法
    
    如果在<servlet>元素中配置了一个<load-on-startup>元素,
    那么WEB应用程序在启动时,就会装载并创建实例对象、以及调用Servlet实例对象的init()方法。
    
    可以在启动的时候为整个WEB应用创建一些必要的的资源或连接。
    但如果所有的Servlet都启动加载,则会大大增加服务器负担,
    而且有些Servlet永远也不会被客户访问到,白白浪费资源,所以从性能角度,应合理利用该特性。
    

    1.2.6ServletConfig对象

    在Servlet的配置文件中,可以使用一个或对个<init-param>标签为Servlet配置一些初始化参数。
    
    当Servlet配置了初始化参数后,web容器在创建Servlet实例对象时,
    会自动将这些初始化参数封装到ServletConfig对象中,并在调用Servlet的init方法时,
    将ServletConfig对象传似给Servlet,开发者可以通过ServletConfig对象得到初始化参数信息。
    

    1.2.7ServletContext对象

    WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的Servlet对象,它代表当前web应用。
    
    ServletConfig对象中维护了ServletContext对象的引用,
    开发者在编写Servlet时,可以通过ServletConfig.getServletContext方法获得该对象。
    
    由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,
    因此Servlet对象之间可以通过ServletContext对象来实现通讯。
    ServletContext对象通常也被称之为Context域对象。
    多个Servlet通过ServletContext对象实现数据共享。要确保注意线程安全。
    可以通过ServletContext对象获取WEB应用的初始化参数。
    可以实现Servlet的转发。getRequestDispatcher()方法
    

    1.2.8Servlet体系结构

    从上图可以看出Servlet规范是基于这几个类运转的,与Servlet主动关联的是三个类:
    ServletConfig、ServletRequest、ServletResponse。这三个类都是通过容器传递给Servlet的。
    ServletConfig接口中的方法都是为了获取这个Servlet的一些配置属性,而这些配置属性可能在Servlet运行时被用到。
    ServletContext就是这些配置属性的上下文环境。
    
    servlet体系结构.png

    1.2.9Servlet中的Session与Cookie

    #Servlet能够给我们提供两部分数据:
    一个是在Servlet初始化时调用init方法设置的ServletConfig,
    它基本包含了Servlet本身和Servlet所运行的Servlet容器中的基本信息。
    另一个是ServletRequest提供的这次请求的HTTP协议信息。
    
    Session与Cookie的作用都是为了保持访问用户与后端服务器的交互状态,各有优缺点。
    然而具有讽刺意味的是它们优点和它们的使用场景又是矛盾的,
    例如使用 Cookie 来传递信息时,随着 Cookie 个数的增多和访问量的增加,
    它占用的网络带宽也很大,试想假如 Cookie 占用 200 个字节,
    如果一天的 PV 有几亿的时候,它要占用多少带宽。
    所以大访问量的时候希望用 Session,但是 Session 的致命弱点是不容易在多台服务器之间共享,所以这也限制了 Session 的使用。
    
    
    #Session正常工作的实现方式:
    >> 基于URL Path Parameter,默认支持
    >> 基于Cookie,若不修改Context中的cookie标识,默认支持
    >> 基于SSL,默认不支持,只有connector.getAttribute("SSLEnabled")为true时才支持。
    

    1.2.10Servlet中的Listener

    整个Tomcat服务器中Listener使用的非常广泛,它是基于观察者模式的,
    Listener的设计对开发Servlet应用程序提供了一种快捷的手段,
    能够方便的从另一个纵向唯独控制程序和数据,
    目前Servlet中提供了5中两类事件的观察者接口,他们分别是:
    >> 4个EventListener类型的
    ServletContextAttributeListener、ServletRequestAttributeListener、
    ServletRequestListener、HttpSessionAttributeListener;
    >> 2 个 LifecycleListeners 类型的
    ServletContextListener、HttpSessionListener。
    
    它们基本上涵盖了整个Servlet生命周期中,你感兴趣的每种事件,
    这些Listener的实现类可以配置在web.xml中的<listener>标签中,
    当然也可以在应用程序中动态添加Listener,
    但是ServletContextListener在容器启动之后就不能再添加新的,
    因为它监听的事件已经不会再出现。
    

    1.2.11Servlet规范相关注解

    Servlet相关注解.png
    Servlet3.0开始提供了注解(annotation),使得不再需要在web.xml文件中进行Servlet的部署描述。
    开发者可以使用@WebServlet注解将一个继承于javax.servlet.http.HttpServlet的类标注为可以处理用户请求的Servlet。   
    
    
    @WebServlet:
    用于修饰一个 Servlet 类,用于部署 Servlet 类。
    
    @WebInitParam:
    用于与 @WebServlet 或 @WebFilter 一起使用,为 Servlet、Filter 配置参数。
    
    @WebListener:
    用于修饰 Listener 类,用于部署 Listener 类
    
    @WebFilter:
    用于修饰 Filter 类,用于部署 Filter 类
    
    @MultipartConfig:
    用于修饰 Servlet,指定该 Servlet 将会负责处理 multipart/form-data 类型的请求(主要用于文件上传)
    
    @ServletSecurity:
    这是一个与 JAAS 有关的注解,修饰 Servlet 指定该 Servlet 的安全与授权控制
    
    @HttpConstraint:
    用于与 @ServletSecurity 一起使用,用于指定该 Servlet 的安全与授权控制
    
    @HttpMethodConstraint:
    用于与 @ServletSecurity 一起使用,用于指定该 Servlet 的安全与授权控制
    
    @HandlesTypes:
    可以动态注册Servlet,Filter,Listener, 如:
    @HandlesTypes(WebApplicationInitializer.class)
    public class SpringServletContainerInitializer implements ServletContainerInitializer {}
    其中@HandlesTypes注解表示CustomServletContainerInitializer 可以处理的类,
    在onStartup 方法中,可以通过Set<Class<?>> c 获取得到。
    (这里也用到了 jdk的 SPI机制)
    
    @MultipartConfig:
    用于文件的上传.
    

    1.3 Servlet规范在spring中的应用

    SpringServletContainerInitializer.png Servlet4.1规范中SpringServletContainerInitializer何时启动.png spring中SpringServletContainerInitializer的实现机制01.png spring中SpringServletContainerInitializer的实现机制02.png

    spring中嵌入式容器 tomcat的启动流程

    #过程分析:
    tomcat启动
    --->jdk-spi
    --->SpringServletContainerInitializer(ServletContainerInitializer)
    
    
    完成了如下流程:
    servlet规范->tomcat->spring 初始化(spring容器及servlet注册)
    

    https://cloud.tencent.com/developer/article/1497586

    https://www.cnblogs.com/rocomp/p/4808924.html (servlet原理)
    https://www.jianshu.com/p/230878a836f9 (ServletContainerInitializer)
    https://cloud.tencent.com/developer/article/1497586 (ServletContainerInitializer)

    相关文章

      网友评论

        本文标题:Servlet & Servlet容器

        本文链接:https://www.haomeiwen.com/subject/zbpydctx.html