小马哥是一个非常牛逼的技术大牛,最近在看他的课,感兴趣也可以关注一波小马哥(不是引流,是真的很推荐):
小马哥B站

什么是Servlet

Servlet 是一种基于 Java 技术的 Web 组件,用于生成动态内容,由容器管理。类似于其他 Java 技术组件,Servlet 是平台无关的 Java 类组成,并且由 Java Web 服务器加载执行。通常情况,由 Servlet 容器提供运行时环境。Servlet 容器,有时候也称作为Servlet 引擎,作为Web服务器或应用服务器的一部分。通过请求和响应对话,提供Web客户端与 Servlets 交互的能力。容器管理Servlets实例以及它们的生命周期。
相关技术:
CGI – 基于进程,php, apache httpd CGI
Servlet-基于线程

servlet主要版本

规范版本发布时间Java平台主要更新
Servlet4.02017JavaEE8支持http/2
Servlet3.12013JavaEE7非阻塞I/O,http协议更新机制(websoket)
Servlet3.02009JavaEE6可插拔、简化部署、异步servlet,安全,文件上传
Servlet2.52005JavaEE5Annotation支持
Servlet2.42003J2EE1.4web.xml支持xml scheme
Servlet2.32001J2EE1.3新增filter,事件/监听器,Wrapper
Servlet2.21999J2EE1.2作为J2ee的一部分,以.war文件作为独立web应用

补充知识:
zip,jar,war,ear 其本质都是zip的拓展,都是压缩文件。war和jar拓展名不一样内容是一样的。

Servlet 核心API

核心组件API说明起始版本SpringFrameWork代表实现
javax.servlet .Servlet动态内容组件1.0DispatcherServlet
javax.servlet.FilterServlet过滤器2.3CharacterEncodingFilter
javax.servlet .ServletContextServlet 应用上下文
javax.servlet .AsyncContext异步上下文3.0
javax.servlet.ServletContextListenerServletContext 生命周期监听器2.3ContextLoaderListener
javax.servlet.ServletRequestListenerServletRequest 生命周期监听器2.3RequestContextListener
javaxservlet.http.HttpSessionListenerHttpSession 生命周期监听器2.3HttpSessionMutexListener
javax.servlet.AsyncListener异步上下文监听器3.0StandardServletAsyncWebRequest
javax.servlet.ServletContainerInitializerServlet 容器初始化器3.0Springservletcoptelyong

Servlet 组件注册方式

  • 传统web.xml注册方式 (写xml)
  • 注解方式(servlet 3.0 +)注解@WebServlet
  • 编码注册方式(servlet 3.0 +)

    注册完成以后返回句柄,可以添加映射:

Servlet 生命周期

  • 声明(应用行为)
  • 注册(容器行为 )
  • 初始化: Servlet#initServletConfig)
  • 服务: Servlet#service(ServletRequest, ServletResponse)
  • 销毁: Servlet#destroy()

Filter生命周期

  • 声明(应用行为)
  • 注册(容器行为)
  • 初始化:Filter#init(FilterConfig)
  • 过滤:Filter#doFilter(ServletRequest,ServletResponse,FilterChain)
  • 毁:Filter#destroy()

ServletContext 生命周期

  • 声明(应用行为)
  • 注册(容器行为)
  • 初始化:ServletContextListener#contextInitialized
  • 销毁:ServletContextListener#contextDestroyed

注:
Servlet规范重点章节 2,3,4,5,9,11,12 规范链接
CHAPTER 2 The Servlet Interface
CHAPTER 3 The Request
CHAPTER 4 Servlet Context
CHAPTER 5 The Response
CHAPTER 9 Dispatching Requests(非常重要)
CHAPTER 11Application Lifecycle Events
CHAPTER 12 Mapping Requests to Servlets(非常重要)
还需要看TomcatNIO
并非请求头(header)和请求体(body)都是异步读取的,要看Servlet容器的实现模型。
Tomcat官方文档

关于Tomcat 的一个优化

目前我们都不使用jsp了所以我们可以将jsp的servlet关掉。在tomcat中将此Servlet注释掉。

<servlet><servlet-name>jsp</servlet-name><servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class><init-param><param-name>fork</param-name><param-value>false</param-value></init-param><init-param><param-name>xpoweredBy</param-name><param-value>false</param-value></init-param><load-on-startup>3</load-on-startup></servlet>

关于Tomcat处理静态文件,使用了默认的servlet 来处理

因为jspServerlet 只是匹配jsp文件,要匹配静态文件我们需要用DefaultServlet来匹配。各个服务平台往往都是用default来命名,在springboot里静态文件的处理是forward(这个就是转发请求到下一个servlet) 到对应平台的Servlet来处理,从而适配了。所以在springboot 里面将css 和js文件放到static文件下面就可以读取到。
源码:

public class DefaultServletHttpRequestHandler implements HttpRequestHandler, ServletContextAware {// 这里定义了不同平台处理静态文件的servlet 名称private static final String COMMON_DEFAULT_SERVLET_NAME = "default";private static final String GAE_DEFAULT_SERVLET_NAME = "_ah_default";private static final String RESIN_DEFAULT_SERVLET_NAME = "resin-file";private static final String WEBLOGIC_DEFAULT_SERVLET_NAME = "FileServlet";private static final String WEBSPHERE_DEFAULT_SERVLET_NAME = "SimpleFileServlet";@Nullableprivate String defaultServletName;@Nullableprivate ServletContext servletContext;public DefaultServletHttpRequestHandler() {}public void setDefaultServletName(String defaultServletName) {this.defaultServletName = defaultServletName;}public void setServletContext(ServletContext servletContext) {this.servletContext = servletContext;if (!StringUtils.hasText(this.defaultServletName)) {if (this.servletContext.getNamedDispatcher("default") != null) {this.defaultServletName = "default";} else if (this.servletContext.getNamedDispatcher("_ah_default") != null) {this.defaultServletName = "_ah_default";} else if (this.servletContext.getNamedDispatcher("resin-file") != null) {this.defaultServletName = "resin-file";} else if (this.servletContext.getNamedDispatcher("FileServlet") != null) {this.defaultServletName = "FileServlet";} else {if (this.servletContext.getNamedDispatcher("SimpleFileServlet") == null) {throw new IllegalStateException("Unable to locate the default servlet for serving static content. Please set the 'defaultServletName' property explicitly.");}this.defaultServletName = "SimpleFileServlet";}}}public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Assert.state(this.servletContext != null, "No ServletContext set");RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);if (rd == null) {throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" + this.defaultServletName + "'");} else {// 分发到对应的servlet 进行处理 因为他们都遵循了同一个规范rd.forward(request, response);}}}

关于default servlet 处理静态文件的一个配置示例

<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping><servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>

注解:
关于forward 的时候会不会经过过滤链,这需要在过滤链进行配置。关于执行顺序,先定义mapping的filter优先。

<filter-mapping><filter-name>CharsetEncodingFilter</filter-name><url-pattern>/*</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>FORWARD</dispatcher><dispatcher>INCLUDE</dispatcher><dispatcher>ERROR</dispatcher></filter-mapping>

课堂上的补充知识点:
SPI:spi加载机制

关于打包

使用tomcat打包插件将项目打包为可执行的jar文件

<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><enableNaming>true</enableNaming><tomcatConfigurationFilesDirectory>src/main/webapp/META-INF/conf/</tomcatConfigurationFilesDirectory></configuration></execution></executions></plugin>

顺便也补充一个web.xml,关于映射路径规则可以详情见12章,同时补充/ 与/星号的区别,/星号如果配置了就会匹配所有的路径,所有的请求都会走这个Servlet, 所以/星号一般是配在过滤器上。/与/*的区别

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" metadata-complete="true" version="3.0"><servlet><servlet-name>FrontControllerServlet</servlet-name><servlet-class>FrontControllerServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>FrontControllerServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><display-name>Archetype Created Web Application</display-name><filter><filter-name>CharsetEncodingFilter</filter-name><filter-class>filter.CharsetEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>CharsetEncodingFilter</filter-name><url-pattern>/*</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>FORWARD</dispatcher><dispatcher>INCLUDE</dispatcher><dispatcher>ERROR</dispatcher></filter-mapping><servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class><init-param><param-name>debug</param-name><param-value>0</param-value></init-param><init-param><param-name>listings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>default</servlet-name><url-pattern>*.css</url-pattern></servlet-mapping><servlet-mapping><servlet-name>default</servlet-name><url-pattern>*.js</url-pattern></servlet-mapping></web-app>