1. Servlet介绍
Servlet是基于Java技术的web组件,容器托管的,用于生成动态内容。Servlet容器是web server或application server 的一部分,提供基于请求/响应发送模型的网络服务,解码基于 MIME 的请求,并且格式化基于 MIME 的响应。 Servlet 容器也包含了管理 Servlet 生命周期。
Servlet有三大组件,Filter过滤器、Listener监听器、Servlet,以及ServletContext上下文。
Servlet3.1需支持Http/1.0、Http/1.1、及RFC2612缓存机制,所谓缓存即可能在将客户端请求交给 Servlet 处理之前修改它们,也可能在将 Servlet 生成的响应发送给客户端之前修改它们,或者可能根据 RFC2616 规范直接对请求作出响应而不交给 Servlet 进行处理。
Servlet容器即可以运行在Web服务器的同一个进程中,也可以运行在不同进程中,甚至可以运行在不同主机的进程中。
Servlet3.0支持以下几个主要特性:
- 异步Servlet
- 注解配置
- 可插拔性(pluggability)支持
- ServletContext运行时动态部署
- 支持上传文件
- 非阻塞IO
1.1 Servlet接口
Servlet接口是 Java Servlet API 的核心抽象。所有Servlet 类必须直接或间接的实现该接口,或者更通常做法是通过继承一个实现了该接口的类从而复用许多共性功能。
- GenericServlet
- HttpServlet
HttpServlet抽象子类在 Servlet 接口基础之上添加了些协议相关的方法。其service方法支持“有条件的GET请求”,即如果没有修订,则直接返回304,不调用GET方法,使用客户端缓存。
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
}
注意:在非分布式环境中,Servlet实例在容器中一般是单例的,即Servlet默认是线程不安全的,需要开发人员处理多线程问题。但如果实现了SingleThreadModel接口(作用是保证一个特定 servlet实例的service方法在一个时刻仅能被一个线程执行),则允许在存在多个实例,一般而言看容器如何实现,比如可以使用syncronize进行同步,或采用servlet实例池,该接口在servlet2.4中被废弃,不建议使用。
1.2 Servlet生命周期
Servlet容器负责加载和实例化Servlet。加载和实例化可以发生容器启动时,或者延迟初始化直到容器决定有请求需要处理时。使用的是普通Java类加载机制,可以从本地文件系统,也可以从网络获取。
Servlet在请求处理时实例化或在部署时立即实例化。在后一种情况,以它们的load-on-startup元素表示的顺序实例化。
1.2.1 init初始化
初始化一般用户获取一些代价高昂的资源,比如JDBC,或者执行一些一次性动作。初始化方法为init(ServletConfig config),其中config是每一个servlet实例都会有一个独立的对象,用于获取当前部署描述文件web.xml中配置的信息,如servlet名字、初始化参数、ServletContext对象,如下所示:
<servlet>
<servlet-name>xxx</servlet-name>
<servlet-class>xxx</servlet-class>
<init-param>
<param-name>xxx</param-name>
<param-value>xxx</param-value>
</init-param>
//用于支持文件上传
<multipart-config></multipart-config>
</servlet>
初始化过程中可能抛出UnavailableException异常,而这个异常是说servlet目前暂时无法初始化,需要等待其他资源就绪,请等一段时间再初始化。
//seconds表示等待时间,<=0表示无法预知时间
UnavailableException(String msg, int seconds)
1.2.2 service请求处理
会接收ServletRequest,响应ServletResponse,在Http协议中默认是HttpServletRequest和HttpServletResponse。
注意:
如果抛出UnavailableException表示的是一个永久性不可用,则servlet容器,需要将该servlet从容器中移除,并调用destroy方法。之后会返回一个 SC_NOT_FOUND (404) 响应。
如果 UnavailableException 表示的是一个临时性的不可用,容器可以选择在临时不可用的这段时间内路由任何请求到Servlet。所以在这段时间内被容器拒绝的请求,都会返回一个 SC_SERVICE_UNAVAILABLE (503)响应状态码,且同时会返回一个 Retry-After 头指示此 Servlet 什么时候可用。
容器可以选择忽略永久性和临时性不可用的区别,并把UnavailableExceptions 视为永久性的,从而 Servlet 抛出UnavailableException 后需要把它从服务中移除。
1.2.2.1 upGrade协议升级处理
使用HttpServletRequest.upgrade和HttpUpgradeHandler实现HTTP/1.1协议升级,如升级到Websocket等等.
Client可以在header中发送Upgrade字段,并指定其需要的其他协议,比如HTTP/2.0,此时服务器如果支持需返