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>
<dependency>
<groupId>javax.servlet
</groupId>
<artifactId>javax.servlet-api
</artifactId>
<scope>provided
</scope>
</dependency>
<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>
<path>/
</path>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
配置文件
DefaultAnnotationConfigDispatcherServletInitializer.java
@ComponentScan(basePackages
= "com.whaleson.web.controller")
public class DefaultAnnotationConfigDispatcherServletInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class
<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class
<?>[] getServletConfigClasses() {
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(()->{
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
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
;
}
}