背景
近段时间打算梳理一下近一年用到的SpringBoot及部分相关starter,计划从Web入手。要了解Java开发的Web应用必然的从其标准(Servlet)开始。
以下内容基本来源Oracle官网对Servlet3.0的介绍,由于存在个人理解偏差建议读者直接阅读原文。
地址:https://download.oracle.com/otndocs/jcp/servlet-3.0-mrel-full-oth-JSpec
备注:登录Oracle网站即可将内容以PDF的方式下载下来(简书不支持上传PDF文件)
概念
- Servlet是什么?
servlet是基于Java实现的Web组件,servlet通过servlet容器实现的请求/响应范式。(运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。) - Servlet容器是什么?
servlet容器是Web服务器或应用程序服务器的一部分,它提供发送请求和响应的网络服务,基于MIME解码请求,并格式化基于MIME的响应。一个servlet容器还包含在servlet的生命周期中管理它们。
组成
- Servlet
-
Servlet接口是JavaServletAPI的核心抽象。所有Servlet通过扩展一个实现接口。JavaServletAPI中实现Servlet接口是GenericServlet和HttpServlet。在大多数情况下,开发人员将扩展HttpServlet以实现他们的servlet。
1.1. 通常在开发基于HTTP的Servlet时,Servlet开发人员只需关注HttpServlet中的doGet和doPost方法
1.2. JSP页面本质也是Servlet
屏幕截图 2020-04-12 19.12.14.png - javax.servlet.Servlet接口(生命周期如下:)
2.1. 由Servlet容器调用,执行init方法初始化Servlet,只会执行一次。
2.2. 由servlet容器调用,执行service方法响应servlet请求,每次请求执行一次。注意:service方法是并发执行,方法内容需要考虑同步共享内存
2.3. 由servlet容器调用,执行destroy方法销毁Servelt,只会执行一次。
-
-
Request
- 将来自客户端请求的所有信息封装为一个Request对象。在HTTP协议中,此信息通过HTTP从客户端传输到服务器(注意:也可以自定义其他协议实现)
- javax.servlet.ServletRequest接口
2.1. 方法getServerName:获取当前请求的域名或IP(www.ddblock.com)
2.2. 方法getServerPort:获取当前请求的端口(80)
2.3. 方法getRemoteAddr:获取最后一个请求服务端的客户端IP,如果使用nginx反向代理时需要特殊处理一下
2.4. 方法getRemoterHost:获取最后一个请求服务端的客户端主机名,如果使用nginx反向代理时需要特殊处理一下
2.5. 方法getProtocol:获取当前请求的协议及其版本(HTTP/1.1)
2.6. 方法getScheme:获取当前请求的具体协议(https)
2.7. 方法getCharacterEncoding:获取请求体内容的编码格式
2.8. 方法getContentLength:获取请求体内容的字节长度
2.9. 方法getLocale:获取客户端接收的语言类型
2.10. 方法startAsync:将此请求置于异步模式,调用返回的AsyncContext对象的start执行
2.11. 方法getDispatcherType:获取分发器类型,其中包含FORWARD、 INCLUDE、REQUEST、ASYNC、ERROR
2.12. 方法getServletContext:获取上下文信息
2.13. 方法getAsyncContext:获取异步模式下的上下文
-
ServletContext
- 定义一组servlet用来与其通信的方法。例如,要获取文件的MIME类型,分派请求或写入日志文件。每个Java虚拟机的每个“web应用程序”都有一个上下文。
- javax.servlet.ServletContext接口
2.1. 方法getContextPath:获取上下文根路径
2.2. 方法getResourcePaths:获取指定路径下的下级目录集合
2.3. 方法getMimeType:获取指定文件的MIME类型。通过文件后缀匹配具体MIME类型,具体可参考MimeTypeMappings.properties文件(org/apache/catalina/startup/MimeTypeMappings.properties)
2.4. 方法getRequestDispatcher:获取指定路径的请求分发器,请求分发器通过包装任何类型的资源响应给客户端
2.5. 方法addServlet:用于添加在web.xml、web-fragment.xml配置的Servlet或添加了WebListener注解的Servlet
2.6. 方法addFilter:用于添加在web.xml、web-fragment.xml配置的Filter或添加了WebFilter注解的Filter
2.7. 方法addListener:用于添加在web.xml、web-fragment.xml配置的Listener或添加了WebListener注解的ServletContextListener
-
Response
- 将响应给客户端的所有信息封装为一个Response对象。在HTTP协议中,此信息从服务器传输到客户端通过HTTP头或请求的消息体。
- javax.servlet.ServletResponse接口
2.1. 方法getCharacterEncoding:获取响应body内容的编码格式
2.2. 方法getContentType:获取响应body的内容类型。如:text/html; charset=UTF-8
2.3. 方法setContentLength:填充响应客户端的响应body的字节长度
2.4. 方法getOutputStream:获取ServletOutputStream对象将响应body写入输出流中。getWriter方法也能实现相同功能,但不能同时使用。
2.5. 方法getWriter:获取PrintWriter对象将响应body写入输出流中。getOutputStream方法也能实现相同功能,但不能同时使用。
2.6. 方法setBufferSize:设置临时存储响应内容的缓冲区大小,如果设置比总响应内容小则响应内容会分多次响应给客户端
2.7. 方法flushBuffer:将临时存储响应内容的数据及headers都发送给客户端
-
Filter
- 对资源(servlet或静态内容)的请求与响应执行过滤任务。过滤器在doFilter方法。每个过滤器都可以访问一个FilterConfig对象,从中可以获取其初始化参数,以及对ServletContext的引用,该引用可以用于例如加载过滤任务所需的资源
- javax.servlet.Filter接口
2.1. 由Servlet容器调用,执行init方法初始化Filter,只会执行一次。
2.2. 由servlet容器调用,执行doFilter方法拦截请求与响应,在过滤器链尾端执行servlet,每次请求执行一次。
2.3. 由servlet容器调用,执行destroy方法销毁Filter,只会执行一次。
- Session
- 提供一种在多个页面上标识用户的方法请求或访问网站并存储有关该用户的信息。 servlet容器使用此接口在HTTP客户端和HTTP服务器之间创建会话。会话在指定的时间段内持续存在,并且跨越用户的多个连接或页面请求。一个会话通常对应一个用户,该用户可能会多次访问该站点。服务器可以通过多种方式维护会话,例如使用cookie或重写URL。
- javax.servlet.http.HttpSession接口
2.1. 方法isNew:获取当前请求是否是新的会话
2.2. 方法getMaxInactiveInterval:返回最大时间间隔(以秒为单位),servlet容器将在客户机访问之间保持此会话打开。在此间隔之后,Servlet容器将使会话无效
2.3. 方法invalidate:使该会话无效,然后取消绑定与之绑定的任何对象
2.4. 方法getServletContext:返回此会话所属的ServletContext
2.5. 方法setAttribute、getAttribute:用来存储与获取同一会话的数据
其它说明
- 重要注解
- @WebServlet:用于定义web应用程序中的Servlet组件
@WebServlet(name="MyServlet", urlPatterns={"/foo", "/bar"}) public class SampleUsingAnnotationAttributes extends HttpServlet{ public void doGet(HttpServletRequest req, HttpServletResponse res) { } }
- @WebFilter:定义web应用程序中的过滤器
@WebFilter("/foo") public class MyFilter implements Filter { public void doFilter(HttpServletRequest req, HttpServletResponse res) { } }
- @WebInitParam:用于指定必须传递给Servlet或Filter。是WebServlet和WebFilter的一个属性
- @WebListener:定义对web应用程序上下文各类事件监听的监听器。
javax.servlet.ServletContextListener javax.servlet.ServletContextAttributeListener javax.servlet.ServletRequestListener javax.servlet.ServletRequestAttributeListener javax.servlet.http.HttpSessionListener javax.servlet.http.HttpSessionAttributeListener @WebListener public class MyListener implements ServletContextListener{ public void contextInitialized(ServletContextEvent sce) { ServletContext sc = sce.getServletContext(); sc.addServlet("myServlet", "Sample servlet", "foo.bar.MyServlet", null, -1); sc.addServletMapping("myServlet", new String[] {"/urlpattern/*" }); } }
- javax.servlet.ServletContainerInitializer接口(基于代码配置,而不是web.xml)
- 提供容器初始化的扩展逻辑。容器通过jar查找在容器/应用程序启动时由容器提供的服务API(如下图META-INF/services)。框架提供ServletContainerInitializer的实现必须将一个名为ServletContainerInitializer,根据jar服务API,指向ServletContainerInitializer的实现类。除了ServletContainerInitializer之外,我们还有一个注解handleTypes。实现handleTypes注释ServletContainerInitializer用于表示对可能在handletype或者如果它在类的超级类型。容器使用handleTypes注释来确定何时调用初始值设定项的onStartup方法
@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { @Override public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { } }
2. spring-boot启动web容器时未按照Servlet3.0规范实现,具体可参考(https://blog.csdn.net/weixin_34128501/article/details/92424885),其实现类为org.springframework.boot.web.embedded.tomcat.TomcatStarter 屏幕截图 2020-04-15 23.30.42.png
-
javax.servlet.RequestDispatcher接口
- 表示从客户端接收请求并将请求发送到服务器上的任何资源(例如servlet,HTML文件或JSP文件)的类。 包含forward与include两种模式。
- forward模式:将请求从Servlet转发到服务器上的另一个资源(Servlet,JSP文件或HTML文件)。这种方法允许一个Servlet对请求进行初步处理,而另一种资源可以生成响应。
- include模式:请求服务器的另外一个资源并将资源作为本Servlet输出的子内容
-
事件通知
- 事件覆盖了ServletContext、HttpSession与ServletRequest的生命周期中。
-
具体事件监听器(混个眼熟)
屏幕截图 2020-04-22 23.12.26.png 屏幕截图 2020-04-22 23.12.13.png
网友评论