zoukankan      html  css  js  c++  java
  • Servlet 4 摘译之Servlet接口篇

    Servlet是可以由Java实现的Web服务器组件动态加载的Java类,能够生成动态内容。

    Servlet容器,有时也叫servlet引擎,负责调用Servlet API。Servlet容器通过“请求-响应”方式实现了servlet和web客户端的通信。Servlet容器需要实现MIME类型的请求和响应的编解码。所有servlet容器都应实现HTTP1.1和HTTP2.0协议,但对于HTTPS的支持不做强制要求。

    Servlet接口

    javax.servlet.GenericServletjavax.servlet.http.HttpServlet是两个常用的javax.servlet.Servlet接口的实现类,其中前者是个抽象类,定义了service抽象方法。通常,开发人员会继承后者实现自己的方法。

    service方法其实是Servlet接口定义的,用于处理来自客户端的请求。每一次请求都会调用一次,因此需要合适的并发机制应对并发请求。

    1 HttpServlet抽象类

    HttpServlet抽象类提供了若干具体的Http协议相关的方法可以被service方法自动调用:

    方法 Http请求
    doGet GET
    doPost POST
    doDelete DELETE
    doHead HEAD
    doOptions OPTIONS
    doTrace TRACE

    HttpServlet抽象类的doHead方法只返回doGet方法的响应的头部;doOptions方法返回的是servlet所支持的http方法;doTrace方法返回的是客户端发送的TRACE方法的头部,主要用来debug。

    Servlet设计目标是作为请求的终点,因此不支持CONNECT方法(主要用于代理)。

    2 一个Servlet

    通常,每一个Sevlet容器在每一个JVM环境里只生成一个Servlet对象。因此,开发人员需要自己处理好并发请求带来的同步问题。

    如果实现了SingleThreadModel接口,那么Servlet容器会维护一个对象池,但此时容器在同一时间只允许一个线程调用其中一个对象。

    SingleThreadModel已经是官方弃用API

    3 Servlet生命周期

    Servlet生命周期通过接口的initservicedestory方法来管理。

    3.1 加载与实例化

    Sevlet容器负责Servlet实现类的加载与实例化,可以是容器启动后立即执行,也可以延迟执行。

    Sevlet容器启动时,必须知晓Servlet实现类的文件位置。可以是本地文件系统,也可以是其他网络系统。

    Sevlet容器使用一般的Java类加载机制来加载Servlet实现类,加载完成后会立即实例化。

    3.2 初始化

    Servlet类实例化完成后,容器应该立刻初始化servlet,并在响应请求之前完成。

    Servlet对象初始化,一般会加载持久化的配置信息,初始化开销较大的对象以及执行其他一次性操作。

    初始化动作通过调用init方法来完成,参数是一个javax.servlet.ServletConfig对象。

    初始化过程有可能会抛出UnavailableException或者ServletException异常。这时,Servlet对象不会进入活跃状态,而是会被容器释放。

    初始化失败后,容器稍后可以尝试实例化并初始化一个新的Servlet对象。

    特别注意

    init方法的调用不同于一般意义的静态方法。
    开发人员必须在init方法成功调用后,才能认为servlet进入可用状态。

    3.3 处理请求

    Servlet对象成功的初始化后,容器就可以处理用户请求了。用户请求包含在ServletRequest的对象中,而Servlet对象的响应通过调用ServletResponse对象方法来完成。这两个对象都是service方法的参数。对于http请求,有相应的HttpServletRequestHttpServletResponse对象。

    需要注意的是,Servlet对象在其整个生命周期内也许不会处理到客户端的请求。

    3.3.1 多线程

    Servlet容器应当能够使用多个线程并发地处理请求。

    3.3.2 处理请求的异常

    Servlet对象在处理请求的过程中有可能会抛出ServletException或者UnavailableException

    前者表示Servlet对象在处理过程中出错,该异常应当Servlet容器被妥善处理。

    后者表示Servlet对象无法处理请求。如果是永久性的无法处理,容器应该调用destory方法释放Servlet对象,解除活跃状态。所有因此而拒绝的请求都应该接受到SC_NOT_FOUND404返回状态码。如果是临时性的无法处理,容器应该拒绝向Servlet对象转发请求,并返回SC_SERVICE_UNAVAILABLE503返回状态码,而且响应头部应该包含Retry-After字段,说明该临时性状态何时解除。

    3.3.3 异步处理

    Servlet容器支持异步的处理请求。容器可以有多条线程:一些在组织响应报文,调用complete方法;另一些可能在调用AsyncContext.dispatch方法分发请求。

    一个典型的异步调用流程应该是:

    1. Servlet对象接收请求,开始处理
    2. Servlet对象发送耗时请求
    3. Servlet对象返回,没有响应
    4. 当请求资源可用时,处理请求的线程可以选择继续执行,也可以通过AsyncContext.start将该任务分发至容器中的其他资源(下面是官方文档的原文)

    第十五章“Web Application Environment”和“Propagation of Security Identity in EJBTM Calls”两节中提到的特性,适用于初期响应请求的线程,或者请求通过AsyncContext.dispatch方法分发至容器。 其他线程可以通过AsyncContext.start(Runnable) 方法直接操作响应对象。

    @WebServlet@WebFilter注解有一个布尔属性asyncSupported,默认值为false。如果这个属性为true,调用startAsync可以在不同的线程中异步的处理请求,传参为请求和响应对象的指针,然后在初始线程中返回。响应对象会按照请求对象经过的过滤器链逆序返回。当AsyncContext调用complete方法后,响应对象才会定型。当异步任务正在执行,但startAsync方法还在分发任务时,【应用】应该负责处理对响应对象和请求对象的并发获取。

    asyncSupported属性为trueServlet对象可以向属性为falseServlet对象分发请求。这种情况下,后者的service方法退出的时候,响应对象才会定型。而容器需要调用AsyncContext.complete方法已通知感兴趣的AsyncListener对象。过滤器应该调用AsyncListener.onComplete方法清楚其所关联的资源,保证异步任务的成功返回。

    同步Servlet对象向异步Servlet对象分发任务是非法的。但是IllegalStateException异常会在调用startAsync方法的抛出。因此,同步Servlet对象可以及时转成异步类型。

    This would allow a servlet to either function as a synchronous or an asynchronous servlet.

    AsyncContext.dispatch方法可以实现:异步任务在任意线程上执行,向响应对象中写入内容。这个线程未必知道请求所经过的过滤器链。所以过滤器必须在请求传入的时候,包装响应对象。这样,写入响应对象的内容,仍然要被过滤器所处理。这样就保证了在任意线程向响应对象写入内容的效果是一致的。

  • 相关阅读:
    【Nginx】ngx_event_core_module模块
    ELMAH--Using HTTP Modules and Handlers to Create Pluggable ASP.NET Components 77 out of 90 rated th
    nyist oj 214 单调递增子序列(二) (动态规划经典)
    java 入门书籍(java7)
    ARCGIS将WGS84坐标投影到高斯平面
    【linux】linux下对java程序生成dump文件,并使用IBM Heap Analyzer进行分析,查找定位内存泄漏的问题代码
    【springboot】【socket】spring boot整合socket,实现服务器端两种消息推送
    【linux】linux修改open file 大小
    【docker】docker限制日志文件大小的方法+查看日志文件的方法
    【docker】docker部署spring boot服务,但是docker logs查看容器输出控制台日志,没有日志打印,日志未打印,docker logs不打印容器日志
  • 原文地址:https://www.cnblogs.com/rim99/p/8449939.html
Copyright © 2011-2022 走看看