JavaEE系列(一)--Servlet技术

现在Python和Java是比较流行的两种编程语言,其中使用Java的开发者中大部分从事Web方面的工作(桌面程序市场不大)。所以对于Java开发者来说掌握JavaSE和JavaEE都是很有必要。尽管现在更多使用spring,springboot,springcloud等优秀的框架来简化开发,但是对于基础的JavaEE技术深入研究也是很有必要。一方面能让我们更清楚的认识到web应用的本质,建立自己完整的技术体系;另一方面也有助于我们学习这些优秀框架的源码(相对来讲JDK的源码比spring等框架的源码还是更容易学习的),正所谓一法通万法通,万事皆由易再难,学习路线会更加平滑。

1.什么是Servlet

①字面上来讲Servlet=Server Applet,服务端小程序。

②对于静态的Web技术来说,Servlet技术基于request-response模型为Web应用提供动态的面向用户的内容(即dynamic web)。

③通常说的Servlet本质上是实现Servlet接口的Java类(包括通用的GenericServlet ,处理Http请求的HttpServlet,以及自定义的Servlet等),通过Servlet容器(即Web服务器,如Tomcat,Jetty,WebLogic等)处理客户端的请求并作出响应。

2.Servlet接口

Servlet接口定义了Servlet的生命周期,及获取Servlet信息,上下文的顶层规范。

①Servlet定义了生命周期方法:init,service,destroy
* 生命周期执行顺序:
* Step1:Servlet容器调用Servlet实现的构造方法,创建Servlet实例
* Step2:调用init方法进行初始化(对于每个Servlet实例只初始化一次),例如加载ServletConfig
* Step3:调用service方法,处理客户端请求
* Step4:调用destroy方法,通常在移除Web容器时执行
* Step5:进行GC和销毁Servlet实例
②Servlet提供getServletConfig方法,获取Servlet配置信息
* getServletInfo方法获取Servlet自身的基本信息,例如作者,版本,版权
③ 实现Servlet接口通常采用两种方式:继承GenericServlet和继承HttpServlet

在介绍GenericServlet之前, 这里重点提一下,为什么GenericServlet中定义了

private transient ServletConfig config;

用于存储初始化时的ServletConfig信息。

3.GenericServlet和ServletConfig

  ①GenericServlet是通用的与协议无关的Servlet,如果使用Http协议可以使用HttpServlet(Servlet技术不限于Http协议)。

通过实现ServletConfig接口扩展Servlet的功能(配合定义的transient ServletConfig config属性,可以对初始化的ServletConfig进行操作,我们这点要掌握这种思想)。

 ②ServletConfig用于Servlet容器向Servlet传递信息(在初始化Servlet时,调用Servlet的init(ServletConfig config)方法)。

根据定义的方法可以看出ServletConfig可以获取ServletName,初始化参数和ServletContext(即Servlet上下文,用于Servlet容器和Servlet交互)。

4.ServletContext

 可以深刻的理解:每个JVM中只有一个ServletContext,并对应一个web应用(用万物皆对象的思想来解释,可以理解为一个ServletContext就是指代war包,也就是我们的一个Web应用)

在分布式中,多个JVM中的同一个Web应用 的不同ServletContext实例是不能共享全局信息的(这个很好理解,不同虚拟机的ServletContext实例不同,可以通过数据库技术实现信息共享)。

这里学习一下ServletContext中的方法主要分两类:获取Servlet容器相关的信息,获取当前Web应用的信息。

①Servlet容器相关

public ServletContext getContext(String uripath);获取当前Servlet容器中的其他Web应用的ServletContext对象。

public int getMajorVersion();等获取支持版本的信息的几个方法

public Set<String> getResourcePaths(String path);等获取资源信息的几个方法

public Object getAttribute(String name);获取容器属性

②Web应用相关

String getContextPath();获取当前ServletContext的路径

public RequestDispatcher getRequestDispatcher(String path);获取请求分配对象

public String getInitParameter(String name);获取应用的初始化参数

以及动态添加Servlet,Filter,Listener的几个方法

总结:ServletContext代表一个Web应用,用于Servlet容器与Web应用进行交互。

5.HttpServlet

由于Web应用通常使用http协议,通常可以继承HttpServlet编写自定义的Servlet类。

这里认真理解一下HttpServlet的源码

①doGet方法

  如果处理get请求需要重写doGet方法。Get请求用于处理幂等性操作(如查询类操作,如需改变数据使用其他请求方法)。

②doHead方法

 doHead请求用户处理只需要响应头,而不需要响应体的请求。doHead方法也要求幂等性

③doPost方法

 doPost方法对请求数据长度没有限制,并且doPost方法不要求幂等性(可以执行变更数据的操作)。

④doPut方法

 doPut方法用于传输文件,并且不能修改请求头,如果Servlet不能处理请求头,请求将被丢弃响应501。doPut方法不要求幂等性,可用于存储临时文件

⑤doDelete方法

 doDelete方法用于删除服务器中的文档或者web页面,doDelete方法不要求幂等性

⑥doOptions方法用于获取当前服务器支持的http方法有哪些(TRACE,OPTION方法默认支持,可以参考doOptions方法的源码)。

这里学习一下getAllDeclaredMethods()用于获取当前类和父类所有的声明方法。

⑦doTrace方法用于debug

⑧service方法将客户端请求调度到处理Http请求的service方法中,并根据不同的方法类型调用对应的do方法。

6.Servlet的基本使用

①以用@WebServlet注解定义Web应用的Servlet组件(也通过xml配置Servlet,这里不再介绍)

通过urlPatterns 或 value 属性定义Servlet的请求路径。

通过@WebInitParam 注解定义初始化参数。

 ②获取请求信息

通过ServleRequest获取BufferedReader 或者ServletInputStream,读取请求信息(参数,属性,协议信息等)

③构造响应

通过 ServletResponse获取PrintWriter 或者ServletOutputStream ,向客户端返回响应信息(设置响应头,响应体,setContentType,设置编码格式,状态码,Cookie等)

这里尤其要注意PrintWriter 和ServletOutputStream是互斥的只能获取其中一个用于响应。

setContentType通常为MIME类型,可以参考http://www.iana.org/assignments/media-types/

7.异步Servlet和NIO

Servlet3支持异步的操作,下图展示同步和异步操作的区别:

 

在异步Servlet中使用非阻塞IO(例子给出了处理输入,作为参照可以也使用NIO处理输出):

 8.Servlet线程不安全

  ①由于容器的多线程引起的线程不安全性

②不同Servlet之间的线程不安全性

③如果单个Servlet实现中使用多线程也有可能造成线程安全问题。

9.总结

 Servlet相关的主要内容学习完毕,一些HttpServletRequest等不做过多研究,事件监听机制后续介绍。

知识点:Servlet用于处理请求响应,运行在Servlet容器中,ServletContext指代Web应用,以及Servlet线程安全问题。

通过这次系统的学习,对Servlet体系有了更深入的认识。

原文地址:https://www.cnblogs.com/masting/p/12783848.html