小马哥训练营-Java EE单体架构

什么是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 +)
    在这里插入图片描述
    注册完成以后返回句柄,可以添加映射:
    小马哥训练营-Java EE单体架构_第1张图片

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官方文档
小马哥训练营-Java EE单体架构_第2张图片

关于Tomcat 的一个优化

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

<servlet>
    <servlet-name>jspservlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServletservlet-class>
    <init-param>
        <param-name>forkparam-name>
        <param-value>falseparam-value>
    init-param>
    <init-param>
        <param-name>xpoweredByparam-name>
        <param-value>falseparam-value>
    init-param>
    <load-on-startup>3load-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";
    @Nullable
    private String defaultServletName;
    @Nullable
    private 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>defaultservlet-name>
     <url-pattern>/url-pattern>
 servlet-mapping>
 <servlet-mapping>
     <servlet-name>defaultservlet-name>
     <url-pattern>*.cssurl-pattern>
 servlet-mapping>
 <servlet-mapping>
     <servlet-name>defaultservlet-name>
     <url-pattern>*.jsurl-pattern>
 servlet-mapping>
      <servlet>
       <servlet-name>defaultservlet-name>
       <servlet-class>org.apache.catalina.servlets.DefaultServletservlet-class>
       <init-param>
           <param-name>debugparam-name>
           <param-value>0param-value>
       init-param>
       <init-param>
           <param-name>listingsparam-name>
           <param-value>falseparam-value>
       init-param>
       <load-on-startup>1load-on-startup>
   servlet>

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

<filter-mapping>
    <filter-name>CharsetEncodingFilterfilter-name>
    <url-pattern>/*url-pattern>
    
    <dispatcher>REQUESTdispatcher>
    <dispatcher>FORWARDdispatcher>
    <dispatcher>INCLUDEdispatcher>
    <dispatcher>ERRORdispatcher>
filter-mapping>

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

你可能感兴趣的:(Java,java-ee,架构,笔记)