Spring Boot 2.0深度实践之核心技术篇【第七节 渐行渐远的 Servlet】

it2023-11-15  74

7-1 渐行渐远的Servlet

Spring5开始支持WebFlux,把以前Java Web应用开发从Servlet必 选变成可选,一个是Servlet Web,另外一个是React Web(WebFlux)

技术回顾

传统Servlet部署 通过web.xml 传统Servlet组件 Servlet API本身FilterListener:ServletContextListener HandlerMethodReturnValueHandler 关于异步Servlet实现 DispatcherServletWeb自动装配

什么是 Servlet?

Servlet是一种基于Java技术的 Web组件,用于生成动态内容,由容器管理。类似于其他Java技术组件,Servlet是平台无关的 Java类组成,并且由 Java Web服务器加载执行。通常情况,由 Servlet 容器提供运行时环境。Servlet容器,有时候也称作为 Servlet引擎,作为Web服务器或应用服务器的一部分。通过请求和响应对话,提供Web客户端与 Servlets交互的能 力。容器管理Servlets实例以及它们的生命周期。 从功能上,Servlet介于 CGI(Common Gateway Interface)与服务扩展(如:Netscape Server API或 Apache模块)之间。 在体系上,Servlet技术(或者规范)属于Java EE技术(规范)的一部分。不过 Servlet 并非一开始就隶属于 J2EE或者Java EE。接下来的小节将会介绍 Servlet各个版本。

Servlet版本

规范版本发布时间Java 平台主要更新Servlet 4.02017 年 9 月Java EE 8支持 HTTP/2Servlet 3.12013 年 5 月Java EE 7非阻塞 I/O、HTTP 协议更新机制(WebSocket)Servlet 3.02009 年 12 月Java EE 6可插拔、简化部署、异步 Servlet、安全、文件上传Servlet 2.52005 年 9 月Java EE 5Annotation 支持Servlet 2.42003 年 11月J2EE 1.4web.xml 支持 XML SchemeServlet 2.32001 年 8月J2EE 1.3新增 Filter、事件/监听器、WrapperServlet2.2 1999 年 8月J2EE 1.2作为 J2EE 的一部分, 以 .war 文件作为独立 web 应用

7-2 Servlet 核心 API

核心组件API 说明起始版本Spring Framework 代表实现javax.servlet.Servlet动态内容组件1.0DispatcherServletjavax.servlet.FilterServlet 过滤器2.3CharacterEncodingFilterjavax.servlet.ServletContextServlet应用上下文javax.servlet.AsyncContext异步上下文3.0无javax.servlet.ServletContextListenerServletContext 生命周期监听器2.3ContextLoaderListenerjavax.servlet.ServletRequestListenerServletRequest生命周期监听器2.3RequestContextListenerjavax.servlet.http.HttpSessionListenerHttpSession 生命周期监听器2.3HttpSessionMutexListenerjavax.servlet.AsyncListener异步上下文监听器3.0StandardServletAsyncWebRequestjavax.servlet.ServletContainerInitializerServlet 容器初始化器3.0SpringServletContainerInitializer

7-4 Servlet 注册

注册方式传统方式注解方式编程方式Servlet注册web.xml部署 <servlet> + <servlet-mapping>@WebServletServletContext#addServletFilter注册web.xml部署 <filter> + <filter-mapping>@WebFilterServletContext#addFilter*Listener注册web.xml部署 <listener>@WebListenerServletContext#addListener <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/webapp_2_5.xsd" metadata-complete="true" version="2.5"> <context-param> <description> Spring 配置文件路径参数,该参数值将被 org.springframework.web.context.ContextLoaderListener 使用 </description> <param-name>contextConfigLocation</param-name> <param-value> classpath*:/META-INF/spring/spring-context.xml </param-value> </context-param> <listener> <description> org.springframework.web.context.ContextLoaderListener 为可选申明Listener </description> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> </web-app>

7-5 理解 Servlet 组件生命周期

理解 Servlet生命周期

初始化:init(ServletConfig)服务: service(ServletRequest,ServletResponse)销毁: destroy()
DispatcherServlet初始化过程
#mermaid-svg-6AuZnnpzWmNqMSzy .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .label text{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .node rect,#mermaid-svg-6AuZnnpzWmNqMSzy .node circle,#mermaid-svg-6AuZnnpzWmNqMSzy .node ellipse,#mermaid-svg-6AuZnnpzWmNqMSzy .node polygon,#mermaid-svg-6AuZnnpzWmNqMSzy .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-6AuZnnpzWmNqMSzy .node .label{text-align:center;fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .node.clickable{cursor:pointer}#mermaid-svg-6AuZnnpzWmNqMSzy .arrowheadPath{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-6AuZnnpzWmNqMSzy .flowchart-link{stroke:#333;fill:none}#mermaid-svg-6AuZnnpzWmNqMSzy .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-6AuZnnpzWmNqMSzy .edgeLabel rect{opacity:0.9}#mermaid-svg-6AuZnnpzWmNqMSzy .edgeLabel span{color:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-6AuZnnpzWmNqMSzy .cluster text{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-6AuZnnpzWmNqMSzy .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-6AuZnnpzWmNqMSzy text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-6AuZnnpzWmNqMSzy .actor-line{stroke:grey}#mermaid-svg-6AuZnnpzWmNqMSzy .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-6AuZnnpzWmNqMSzy #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .sequenceNumber{fill:#fff}#mermaid-svg-6AuZnnpzWmNqMSzy #sequencenumber{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy #crosshead path{fill:#333;stroke:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .messageText{fill:#333;stroke:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-6AuZnnpzWmNqMSzy .labelText,#mermaid-svg-6AuZnnpzWmNqMSzy .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-6AuZnnpzWmNqMSzy .loopText,#mermaid-svg-6AuZnnpzWmNqMSzy .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-6AuZnnpzWmNqMSzy .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-6AuZnnpzWmNqMSzy .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-6AuZnnpzWmNqMSzy .noteText,#mermaid-svg-6AuZnnpzWmNqMSzy .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-6AuZnnpzWmNqMSzy .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-6AuZnnpzWmNqMSzy .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-6AuZnnpzWmNqMSzy .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-6AuZnnpzWmNqMSzy .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy .section{stroke:none;opacity:0.2}#mermaid-svg-6AuZnnpzWmNqMSzy .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-6AuZnnpzWmNqMSzy .section2{fill:#fff400}#mermaid-svg-6AuZnnpzWmNqMSzy .section1,#mermaid-svg-6AuZnnpzWmNqMSzy .section3{fill:#fff;opacity:0.2}#mermaid-svg-6AuZnnpzWmNqMSzy .sectionTitle0{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .sectionTitle1{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .sectionTitle2{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .sectionTitle3{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-6AuZnnpzWmNqMSzy .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy .grid path{stroke-width:0}#mermaid-svg-6AuZnnpzWmNqMSzy .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-6AuZnnpzWmNqMSzy .task{stroke-width:2}#mermaid-svg-6AuZnnpzWmNqMSzy .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy .taskText:not([font-size]){font-size:11px}#mermaid-svg-6AuZnnpzWmNqMSzy .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-6AuZnnpzWmNqMSzy .task.clickable{cursor:pointer}#mermaid-svg-6AuZnnpzWmNqMSzy .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-6AuZnnpzWmNqMSzy .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-6AuZnnpzWmNqMSzy .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-6AuZnnpzWmNqMSzy .taskText0,#mermaid-svg-6AuZnnpzWmNqMSzy .taskText1,#mermaid-svg-6AuZnnpzWmNqMSzy .taskText2,#mermaid-svg-6AuZnnpzWmNqMSzy .taskText3{fill:#fff}#mermaid-svg-6AuZnnpzWmNqMSzy .task0,#mermaid-svg-6AuZnnpzWmNqMSzy .task1,#mermaid-svg-6AuZnnpzWmNqMSzy .task2,#mermaid-svg-6AuZnnpzWmNqMSzy .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-6AuZnnpzWmNqMSzy .taskTextOutside0,#mermaid-svg-6AuZnnpzWmNqMSzy .taskTextOutside2{fill:#000}#mermaid-svg-6AuZnnpzWmNqMSzy .taskTextOutside1,#mermaid-svg-6AuZnnpzWmNqMSzy .taskTextOutside3{fill:#000}#mermaid-svg-6AuZnnpzWmNqMSzy .active0,#mermaid-svg-6AuZnnpzWmNqMSzy .active1,#mermaid-svg-6AuZnnpzWmNqMSzy .active2,#mermaid-svg-6AuZnnpzWmNqMSzy .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-6AuZnnpzWmNqMSzy .activeText0,#mermaid-svg-6AuZnnpzWmNqMSzy .activeText1,#mermaid-svg-6AuZnnpzWmNqMSzy .activeText2,#mermaid-svg-6AuZnnpzWmNqMSzy .activeText3{fill:#000 !important}#mermaid-svg-6AuZnnpzWmNqMSzy .done0,#mermaid-svg-6AuZnnpzWmNqMSzy .done1,#mermaid-svg-6AuZnnpzWmNqMSzy .done2,#mermaid-svg-6AuZnnpzWmNqMSzy .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-6AuZnnpzWmNqMSzy .doneText0,#mermaid-svg-6AuZnnpzWmNqMSzy .doneText1,#mermaid-svg-6AuZnnpzWmNqMSzy .doneText2,#mermaid-svg-6AuZnnpzWmNqMSzy .doneText3{fill:#000 !important}#mermaid-svg-6AuZnnpzWmNqMSzy .crit0,#mermaid-svg-6AuZnnpzWmNqMSzy .crit1,#mermaid-svg-6AuZnnpzWmNqMSzy .crit2,#mermaid-svg-6AuZnnpzWmNqMSzy .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-6AuZnnpzWmNqMSzy .activeCrit0,#mermaid-svg-6AuZnnpzWmNqMSzy .activeCrit1,#mermaid-svg-6AuZnnpzWmNqMSzy .activeCrit2,#mermaid-svg-6AuZnnpzWmNqMSzy .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-6AuZnnpzWmNqMSzy .doneCrit0,#mermaid-svg-6AuZnnpzWmNqMSzy .doneCrit1,#mermaid-svg-6AuZnnpzWmNqMSzy .doneCrit2,#mermaid-svg-6AuZnnpzWmNqMSzy .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-6AuZnnpzWmNqMSzy .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-6AuZnnpzWmNqMSzy .milestoneText{font-style:italic}#mermaid-svg-6AuZnnpzWmNqMSzy .doneCritText0,#mermaid-svg-6AuZnnpzWmNqMSzy .doneCritText1,#mermaid-svg-6AuZnnpzWmNqMSzy .doneCritText2,#mermaid-svg-6AuZnnpzWmNqMSzy .doneCritText3{fill:#000 !important}#mermaid-svg-6AuZnnpzWmNqMSzy .activeCritText0,#mermaid-svg-6AuZnnpzWmNqMSzy .activeCritText1,#mermaid-svg-6AuZnnpzWmNqMSzy .activeCritText2,#mermaid-svg-6AuZnnpzWmNqMSzy .activeCritText3{fill:#000 !important}#mermaid-svg-6AuZnnpzWmNqMSzy .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-6AuZnnpzWmNqMSzy g.classGroup text .title{font-weight:bolder}#mermaid-svg-6AuZnnpzWmNqMSzy g.clickable{cursor:pointer}#mermaid-svg-6AuZnnpzWmNqMSzy g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-6AuZnnpzWmNqMSzy g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-6AuZnnpzWmNqMSzy .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-6AuZnnpzWmNqMSzy .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-6AuZnnpzWmNqMSzy .dashed-line{stroke-dasharray:3}#mermaid-svg-6AuZnnpzWmNqMSzy #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy .commit-id,#mermaid-svg-6AuZnnpzWmNqMSzy .commit-msg,#mermaid-svg-6AuZnnpzWmNqMSzy .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-6AuZnnpzWmNqMSzy g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-6AuZnnpzWmNqMSzy g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-6AuZnnpzWmNqMSzy g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-6AuZnnpzWmNqMSzy .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-6AuZnnpzWmNqMSzy .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-6AuZnnpzWmNqMSzy .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-6AuZnnpzWmNqMSzy .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-6AuZnnpzWmNqMSzy .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-6AuZnnpzWmNqMSzy .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-6AuZnnpzWmNqMSzy .edgeLabel text{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-6AuZnnpzWmNqMSzy .node circle.state-start{fill:black;stroke:black}#mermaid-svg-6AuZnnpzWmNqMSzy .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-6AuZnnpzWmNqMSzy #statediagram-barbEnd{fill:#9370db}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-state .divider{stroke:#9370db}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-6AuZnnpzWmNqMSzy .note-edge{stroke-dasharray:5}#mermaid-svg-6AuZnnpzWmNqMSzy .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-6AuZnnpzWmNqMSzy .error-icon{fill:#522}#mermaid-svg-6AuZnnpzWmNqMSzy .error-text{fill:#522;stroke:#522}#mermaid-svg-6AuZnnpzWmNqMSzy .edge-thickness-normal{stroke-width:2px}#mermaid-svg-6AuZnnpzWmNqMSzy .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-6AuZnnpzWmNqMSzy .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-6AuZnnpzWmNqMSzy .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-6AuZnnpzWmNqMSzy .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-6AuZnnpzWmNqMSzy .marker{fill:#333}#mermaid-svg-6AuZnnpzWmNqMSzy .marker.cross{stroke:#333} :root { --mermaid-font-family: "trebuchet ms", verdana, arial;} #mermaid-svg-6AuZnnpzWmNqMSzy { color: rgba(0, 0, 0, 0.75); font: ; } HttpServlet.init() HttpServletBean.init() FrameworkServlet.initServletBean() FrameworkServlet.initWebApplicationContext() DispatcherServlet.onRefresh() DispatcherServlet.initStrategies() Servlet 初始化生命周期调用 将 ServletConfig 参绑定到Servlet 字段 初始化 Servlet 关联的 WebApplicationContext 触发 DispatcherServlet onRefresh 初始化 DispatcherServlet 各种组件 HttpServlet.init() HttpServletBean.init() FrameworkServlet.initServletBean() FrameworkServlet.initWebApplicationContext() DispatcherServlet.onRefresh() DispatcherServlet.initStrategies() DispatcherServlet 初始化过程

理解 Filter生命周期

初始化: init(FilterConfig)服务: doFilter(ServletRequest,ServletResponse,FilterChain)销毁: destroy()

理解 ServletContext生命周期

初始化: contextInitialized(ServletContextEvent)销毁: contextDestroyed(ServletContextEvent)

7-6 Servlet 异步支持

DeferredResult支持

DeferredResult——异步请求处理

新建项目spring-servlet

配置pom文件
pom.xml
<packaging>war</packaging> <dependencies> <!-- Servlet 3.1 API 依赖--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <scope>provided</scope> </dependency> <!-- Spring Web MVC 依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.1</version> <executions> <execution> <id>tomcat-run</id> <goals> <goal>exec-war-only</goal> </goals> <phase>package</phase> <configuration> <!-- ServletContext path --> <path>/</path> </configuration> </execution> </executions> </plugin> </plugins> </build> 配置文件
DefaultAnnotationConfigDispatcherServletInitializer.java
@ComponentScan(basePackages = "com.whaleson.web.controller") //@Configuration public class DefaultAnnotationConfigDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { // web.xml return new Class[0]; } @Override protected Class<?>[] getServletConfigClasses() { // DispatcherServlet return new Class[]{ getClass() // 返回当前类 }; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } } Controller

HelloWorldAsyncController.java

@RestController public class HelloWorldAsyncController { @GetMapping("/show/msg") public DeferredResult<String> showAsync(){ DeferredResult<String> result = new DeferredResult<>(); result.onCompletion(()->{ println("I'm Completion!"); }); println("Hello Everyone!!!"); result.setResult("Hello Everyone!!!"); return result; } public static void println(Object object){ String threadName = Thread.currentThread().getName(); System.out.println("当前线程的名称是[" + threadName + "]内容是:" + object); } }

运行

打包

mvn -Dmaven.skip.test -U clean package

运行

java -jar target\spring-servlet-0.0.1-SNAPSHOT-war-exec.jar

浏览器输入Get请求地址

http://localhost:8080/show/msg

浏览器输出结果

Hello Everyone!!!

控制台输出结果

当前线程的名称是[http-bio-8080-exec-2]内容是:Hello Everyone!!! 当前线程的名称是[http-bio-8080-exec-2]内容是:I'm Completion!

结论

当前程序还是同步的,因为是同一个线程。

7-9 DeferredResult 异步执行

实现方式

激活()将结果放到另外一个线程

DefaultAnnotationConfigDispatcherServletInitializer.java -)AbstractAnnotationConfigDispatcherServletInitializer.java -)AbstractDispatcherServletInitializer.registerDispatcherServlet() -) registration.setAsyncSupported(this.isAsyncSupported());

代码实现

HelloWorldAsyncController.java @RestController @EnableScheduling public class HelloWorldAsyncController { private final BlockingQueue<DeferredResult<String>> queue = new ArrayBlockingQueue<DeferredResult<String>>(5); private final Random random = new Random(); @Scheduled(fixedRate = 5000) public void process() throws InterruptedException { DeferredResult<String> result = null; do{ result = queue.take(); long timeout = random.nextInt(3000); //模拟等待时间 Thread.sleep(timeout); //计算结果 result.setResult("Happy Every Day!"); println("执行计算结果"+ timeout + "ms"); }while (result != null); } @GetMapping("/show/msg") public DeferredResult<String> showAsync() throws Exception{ DeferredResult<String> result = new DeferredResult<>(50L); queue.offer(result); println("Hello Everyone!!!"); result.onCompletion(()->{ //相当于finally操作 println("I'm Completion!"); }); result.onTimeout(()->{ println("I'm Timeout"); }); return result; } public static void println(Object object){ String threadName = Thread.currentThread().getName(); System.out.println("当前线程的名称是[" + threadName + "]内容是:" + object); } } 执行结果

当前线程的名称是[http-bio-8080-exec-1]内容是:Hello Everyone!!! 当前线程的名称是[http-bio-8080-exec-3]内容是:I'm Timeout 十月 24, 2020 3:05:15 下午 org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver logException警告: Resolved [org.springframework.web.context.request.async.AsyncRequestTimeoutException] 当前线程的名称是[http-bio-8080-exec-3]内容是:I'm Completion! 当前线程的名称是[pool-1-thread-1]内容是:执行计算结果2000ms

7-10 Callable 异步执行

@GetMapping("/callable") public Callable<String> callableHelloWorld(){ println("Hello World ! My girl!"); long startTime = System.currentTimeMillis(); return () ->{ println("执行程序消耗时间\t" + (System.currentTimeMillis() -startTime)); return "hello world"; }; } 缺点

没有回调;需要回调建议使用ListenableFutureCallback

7-11 CompletionStage 异步执行

关于CompletionStage<T>接口

它的实现有CompletableFuture<T>

HelloWorldAsyncController @GetMapping("/completable") public CompletionStage<String> completionStageHelloWorld(){ long startTime = System.currentTimeMillis(); println("Hello CompletableFuture ! "); return CompletableFuture.supplyAsync(()-> { println("执行程序消耗时间\t" + (System.currentTimeMillis() -startTime)); return "Goodbye CompletableFuture !";//异步执行结果 }); } 浏览器地址

http://localhost:8080/completable

输出结果

当前线程的名称是[http-bio-8080-exec-4]内容是:Hello CompletableFuture ! 当前线程的名称是[ForkJoinPool.commonPool-worker-1]内容是:执行程序消耗时间17

7-12 MVC 异步支持原理分析

Spring Web MVC异步Servlet实现原理
HandlerMethodReturnValueHandlerServlet 3.0 AsyncContextDispatcherServlet整合

7-13 异步 Servlet 实现

Java Specification Requests (JSR)

自定义Servlet继承HttpServlet public class AsyncServlet extends HttpServlet { } 添加类注解WebServlet

@WebServlet

激活异步特性

asyncSupported = true

添加映射

urlPatterns = "/async-servlet"

重写service方法 判断当前请求是否支持异步

req.isAsyncSupported()

创建AsyncContext

AsyncContext asyncContext = req.startAsync();

添加监听器

asyncContext.addListener()

@WebServlet( asyncSupported = true, urlPatterns = "/async-servlet" ) public class AsyncServlet extends HttpServlet { @Override public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (req.isAsyncSupported()) { println("Hey man."); AsyncContext asyncContext = req.startAsync(); asyncContext.setTimeout(50L); asyncContext.addListener(new AsyncListener() { @Override public void onComplete(AsyncEvent event) throws IOException { println("complete"); } @Override public void onTimeout(AsyncEvent event) throws IOException { println("timeout"); } @Override public void onError(AsyncEvent event) throws IOException { println("error"); } @Override public void onStartAsync(AsyncEvent event) throws IOException { println("start"); } }); HttpServletResponse response =(HttpServletResponse) asyncContext.getResponse(); //设置响应媒体类型 response.setContentType("text/plain;charset=UTF-8"); //获取字符输出流 PrintWriter printWriter = response.getWriter(); printWriter.println("Hello"); printWriter.flush(); } } public static void println(Object object) { String threadName = Thread.currentThread().getName(); System.out.println("当前线程的名称是[" + threadName + "]内容是:" + object); } } 浏览器地址

http://localhost:8080/async-servlet

浏览器内容

Hello

控制台内容

当前线程的名称是[http-bio-8080-exec-1]内容是:Hey man. 当前线程的名称是[http-bio-8080-exec-3]内容是:timeout 当前线程的名称是[http-bio-8080-exec-3]内容是:complete

7-14 DefferedResult 实现原理

DeferredResultMethodReturnValueHandler

7-15 Spring Boot 嵌入式 Servlet 容器限制

Servlet 特性兼容性解决方案web.xml不支持RegistrationBean 或 @Bean 注册ServletContainerInitializer不支持ServletContextInitializer@WebServlet 等有限支持依赖 @ServletComponentScan

pom.xml

引入spring-servlet <dependency> <groupId>com.whaleson</groupId> <artifactId>spring-servlet</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>demo</artifactId> <groupId>com.example</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.whaleson</groupId> <artifactId>spring-boot-servlet</artifactId> <dependencies> <dependency> <groupId>com.whaleson</groupId> <artifactId>spring-servlet</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>

SpringBootServletApplication.java

@EnableAutoConfiguration //@ServletComponentScan(basePackages = "com.whaleson.web") public class SpringBootServletApplication { public static void main(String[] args) { SpringApplication.run(SpringBootServletApplication.class,args); } @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public ServletRegistrationBean asyncServletRegistrationBean(){ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new AsyncServlet(),"/async-servlet"); return servletRegistrationBean; } @Bean public ServletContextInitializer servletContextInitializer(){ return servletContext -> { CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); FilterRegistration.Dynamic filterRegistration = servletContext.addFilter("filter",characterEncodingFilter); filterRegistration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),false,"/"); }; } } @ServletComponentScan

该注解扫描的是spring-servlet模块里AsyncServlet.java所在的包

@Order(Ordered.HIGHEST_PRECEDENCE)

asyncServletRegistrationBean()方法中,该注解添加与否都可以。

浏览器地址

http://localhost:8081/async-servlet

浏览器结果

Hello

控制台结果

当前线程的名称是[http-nio-8081-exec-4]内容是:Hey man. 当前线程的名称是[http-nio-8081-exec-3]内容是:timeout 当前线程的名称是[http-nio-8081-exec-3]内容是:complete

7-16 Spring Boot 嵌入式 Servlet 容器限制 原理分析

通过 RegistrationBean注册

ServletContextInitializer RegistrationBean ServletListenerRegistrationBean

@WebListener

FilterRegistrationBean

@WebFilter

ServletRegistrationBean

@WebServlet

@ServletComponentScan扫描 package-> @Web*-> RegistrationBean Bean定义 -> RegistrationBean Bean

7-17 Spring Boot 应用传统 Servlet 容器部署

不支持web.xml部署不支持ServletContainerInitialier接口注解驱动限制

Spring Boot Servlet注册

@Bean方式:RegistrationBean、Servlet组件注解方式:@ServletComponentScan编程方式:ServletContextInitializer

public class DefaultSpringBootServletInitializer extends SpringBootServletInitializer { protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { builder.sources(SpringBootServletApplication.class); return builder; } }
最新回复(0)