小马哥是一个非常牛逼的技术大牛,最近在看他的课,感兴趣也可以关注一波小马哥(不是引流,是真的很推荐):
小马哥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.0 | 2017 | JavaEE8 | 支持http/2 |
Servlet3.1 | 2013 | JavaEE7 | 非阻塞I/O,http协议更新机制(websoket) |
Servlet3.0 | 2009 | JavaEE6 | 可插拔、简化部署、异步servlet,安全,文件上传 |
Servlet2.5 | 2005 | JavaEE5 | Annotation支持 |
Servlet2.4 | 2003 | J2EE1.4 | web.xml支持xml scheme |
Servlet2.3 | 2001 | J2EE1.3 | 新增filter,事件/监听器,Wrapper |
Servlet2.2 | 1999 | J2EE1.2 | 作为J2ee的一部分,以.war文件作为独立web应用 |
补充知识:
zip,jar,war,ear 其本质都是zip的拓展,都是压缩文件。war和jar拓展名不一样内容是一样的。
Servlet 核心API
核心组件API | 说明 | 起始版本 | SpringFrameWork代表实现 |
---|---|---|---|
javax.servlet .Servlet | 动态内容组件 | 1.0 | DispatcherServlet |
javax.servlet.Filter | Servlet过滤器 | 2.3 | CharacterEncodingFilter |
javax.servlet .ServletContext | Servlet 应用上下文 | ||
javax.servlet .AsyncContext | 异步上下文 | 3.0 | 无 |
javax.servlet.ServletContextListener | ServletContext 生命周期监听器 | 2.3 | ContextLoaderListener |
javax.servlet.ServletRequestListener | ServletRequest 生命周期监听器 | 2.3 | RequestContextListener |
javaxservlet.http.HttpSessionListener | HttpSession 生命周期监听器 | 2.3 | HttpSessionMutexListener |
javax.servlet.AsyncListener | 异步上下文监听器 | 3.0 | StandardServletAsyncWebRequest |
javax.servlet.ServletContainerInitializer | Servlet 容器初始化器 | 3.0 | Springservletcoptelyong |
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>