Servlet是什么?
Servlet是JavaEE规范的一种,主要是为了扩展Java作为Web服务的功能,统一接口。由其他内部厂商如tomcat,jetty内部实现web的功能。如一个http请求到来:
容器将请求封装为servlet中的HttpServletRequest对象,调用init(),service()等方法输出response,由容器包装为httpresponse返回给客户端的过程。
在Servlet规范中,提供了ServletContext,ServletRequest,ServletResponse,Filter等诸多接口。
基本类图和调用关系如下:
下面简要介绍下接口的作用,生命周期和使用:
Servlet
:
作用:用于处理请求(service方法)
生命周期:加载实例化、初始化、处理客户端请求、销毁。
加载实例化主要是交由web容器完成,而其他三个阶段则对应Servlet的init、service和destroy方法。Servlet对象被创建出来后需要对其进行初始化操作,初始化工作可以放在以ServletConfig类型为参数的ini方法中,ServletConfig为web.xml配置文件中配置的对应的初始化参数,由web容器完成web.xml配置读取并封装成ServletConfig对象;当Servlet初始化完成后,开始接受客户端的请求,这些请求被封装成ServletRequest类型的请求对象和ServletResponse类型的响应对象,通过service方法处理请求并响应客户端;当一个Servlet需要从web容器中移除时,就会调用对应的destroy方法用于释放所有的资源,并且调用destroy方法之前要保证所有正在执行service方法的线程都完成执行。
使用:servlet规范中定义了
GenericServlet
接口,定义了通用,协议独立的servlet,他们的子接口
HttpServlet
就是用来处理http请求的Servlet,根据http协议扩展了不同方式的请求处理方法,如doPost,doGet.
ServletContext
:Servlet与Servlet容器之间直接通信的接口,一个web应用只独有一个ServletContext.
作用:
- 用于在web应用范围内存取共享数据,如setAttribute(String name, Object object),getAttribute()
- 获取当前Web应用的资源,如getContextPath()
- 获取服务器端的文件系统资源,如getResourceAsStream()
- 输出日志,如log(String msg) : 向Servlet的日志文件中写日志
- 在具体ServletContext 实现中,提供了添加Servlet,Filter,Listener到ServletContext里面的方法
生命周期:和web应用的生命周期一样
使用:一般由web容器实现,如tomcat
Filter
:
作用:用于Web容器对请求和响应做统一处理,例如统一改变HTTP请求内容和响应内容,它可以作用在某个Servlet或一组Servlet
生命周期:加载实例化、初始化(init)、处理客户端请求(doFilter)、销毁(destroy)
使用:在doFilter方法中调用chain.doFilter(request, response)
之前的代码可用来做一些请求校验,之后代码可用来做一些响应包装。
ServletRequest
:封装了客户端请求的所有信息,如果使用HTTP协议通信则包括HTTP协议的请求行和请求头。HTTP协议对应请求对象类型是HttpServletRequest类
作用:
- 获取HTTP协议请求头部,如getHeader、getHeaders
- 获取请求路径,如getContextPath、getServletPath
- 获取cookie的方法,如getCookies
- 获取session的方法,如getSession,session是存储在服务器内存中,返回响应的时候会写入浏览器一个sessionId的cookie,用来标示这一个会话
生命周期:只在servlet的service方法或过滤器的doFilter方法作用域内有效,除非启用了异步处理调用了ServletRequest接口对象的startAsync方法,此时request对象会一直有效,直到调用AsyncContext的complete方法。另外,web容器通常会为了性能而不销毁ServletRequest接口的对象,而是重复利用ServletRequest接口对象。
ServletResponse
:Servlet通过ServletResponse对象来生成响应结果。
作用:定义了一系列与生成响应结果相关的方法,如:
- setCharacterEncoding() —— 设置相应正文的字符编码。响应正文的默认字符编码为ISO-8859-1;
- setContentLength() —— 设置响应正文的长度;
- setBufferSize() —— 设置用于存放响应正文数据的缓冲区的大小
- getBufferSize() —— 获得用于存放响应正文数据的缓冲区的大小;
- reset() —— 清空缓冲区内的正文数据,并且清空响应状态代码及响应头
- resetBuffer() —— 仅仅清空缓冲区的正文数据,不清空响应状态代码及响应头;
- flushBuffer() —— 强制性地把缓冲区内的响应正文数据发送到客户端;
- isCommitted() —— 返回一个boolean类型的值,如果为true,表示缓冲区内的数据已经提交给客户,即数据已经发送到客户端;
- getOutputStream() —— 返回一个ServletOutputStream对象,Servlet用它来输出二进制的正文数据;
- getWriter() —— 返回一个PrinterWriter对象,Servlet用它来输出字符串形式的正文数据;
为了提高输出数据的效率,ServletOutputStream和PrintWriter首先把数据写到缓冲区内。当缓冲区内的数据被提交给客户后,ServletResponse的isComitted方法返回true。
生命周期:ServletResponse接口只在Servlet的service方法或过滤器的doFilter方法作用域内有效,除非它关联的ServletResponse接口调用了startAsync方法启用异步处理,此时ServletResponse接口会一直有效,直到调用AsyncContext的complete方法。另外,web容器通常会为了性能而不销毁ServletResponse接口对象,而是重复利用ServletResponse接口对象。
Listener
:当触发某个事件,如servlet context初始化完成时,需要做一些事情,servlet规范中定义了若干个Listener用于监听这些事件。
作用:用于对特定对象的生命周期和特定事件进行响应处理,主要用于对Session,request,context等进行监控。
监听域对象自身的创建和销毁的事件监听器
- ServletContextListener:ServletContext的创建和销毁:contextInitialized方法和contextDestroyed方法,作为定时器、加载全局属性对象、创建全局数据库连接、加载缓存信息等
- HttpSessionListener:HttpSession的创建和销毁:sessionCreated和sessionDestroyed方法,可用于统计在线人数、记录访问日志等
- ServletRequestListener: ServletRequest的创建和销毁:requestInitialized和requestDestroyed方法
监听域对象中的属性的增加和删除的事件监听器
- ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener接口。
- 实现方法:attributeAdded、attributeRemoved、attributeReplaced
监听绑定到HttpSeesion域中的某个对象的状态的事件监听器(创建普通JavaBean)
- HttpSession中的对象状态:绑定→解除绑定;钝化→活化
- 实现接口及方法:HttpSessionBindingListener接口(valueBound和valueUnbound方法)、HttpSessionActivationListener接口(sessionWillPassivate和sessionDidActivate方法)
tomcat是什么?
tomcat等容器其实就是web服务的实现,暴露端口,按照特定资源URL找到处理的servlet。然后处理请求。
web.xml其实tomcat在启动时候需要加载的配置欢迎页、Filter、Listener、Servlet等类的定义。当然不止加载这些东西,这些东西是需要加载到JVM堆内存中实例化的对象。
Tomcat启动时加载资源主要有三个阶段:
- 第一阶段:JVM相关资源
(1)$JAVA_HOME/jre/lib/ext/*.jar
(2)系统classpath环境变量中的*.jar和*.class
- 第二阶段:Tomcat自身相关资源
(1)$CATALINA_HOME/common/classes/*.class
(2)$CATALINA_HOME/commons/endorsed/*.jar
(3)$CATALINA_HOME/commons/i18n/*.jar
(4)$CATALINA_HOME/common/lib/*.jar
(5)$CATALINA_HOME/server/classes/*.class
(6)$CATALINA_HOME/server/lib/*.jar
(7)$CATALINA_BASE/shared/classes/*.class
(8)$CATALINA_BASE/shared/lib/*.jar
- 第三阶段:Web应用相关资源
(1)具体应用的webapp目录: /WEB-INF/classes/*.class
(2)具体应用的webapp: /WEB-INF/lib/*.jar
在tomcat目录${CATALINA_HOME}/conf
下和web应用目录${CATALINA_HOME}/webapps/WebDemo
(WebDemo为web应用名)下都有web.xml这个文件,但是内容不一样。
Tomcat在激活、加载、部署web应用时,会解析加载${CATALINA_HOME}/conf目录下所有web应用通用的web.xml,然后解析加载web应用目录中的WEB-INF/web.xml。
其实根据他们的位置,我们就可以知道,conf/web.xml文件中的设定会应用于所有的web应用程序,而某些web应用程序的WEB-INF/web.xml中的设定只应用于该应用程序本身。
如果没有WEB-INF/web.xml文件,tomcat会输出找不到的消息,但仍然会部署并使用web应用程序,servlet规范的作者想要实现一种能迅速并简易设定新范围的方法,以用作测试,因此,这个web.xml并不是必要的,不过通常最好还是让每一个上线的web应用程序都有一个自己的WEB-INF/web.xml。
web.xml中可以配置web应用名称,图标,描述,ServletContext上下文参数,Fliter配置,Listener配置,Servlet配置,会话超时配置,MIME类型配置等等。
Spring MVC 是什么?
Spring MVC (SpringBoot)其实就是基于tomcat等这些web容器对我们的CS请求能做更多的事情,如校验,拦截(AOP思想),后期渲染等等,好让我们专注于业务的开发。
Springmvc的核心是一个DispatcherServlet,负责请求的解析,拦截,转发,响应等等。相关类图和请求处理流程为:
其中FrameworkServlet会和Spring的ApplicationContext联系起来,它实现了ApplicationContextAware接口。
当然Spring MVC框架也提供rest访问,从而可实现前后端的分离。
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RestfulWebServiceController {
@GetMapping("/message")
public MyOutputResource getMessage() {
return new MyOutputResource("Hello!");
}
}
参考资料:
Java Servlet 3.1 规范
servlet的本质是什么,它是如何工作的?
Servlet规范总结
【Java.Web】Servlet —— Servlet的类的体系结构
Servlet 工作原理解析
Cookie 与 Session 的区别
Session原理和Tomcat实现分析
An Introduction to Tomcat Servlet Interactions
关于web.xml配置的那些事儿
How Spring Web MVC Really Works