Servlet 源码分析
 
Servlet 结构图
Servlet 和 ServletConfig 都是顶层接口,而 GenericServlet 实现了这两个顶层接口,然后HttpServlet 继承了 GenericServlet 类.所以要实现一个 Servlet 直接就可以继承 HttpServlet
 
 
Servlet 接口:
 
public interface Servlet {
    //负责初始化 Servlet 对象。容器一旦创建好 Servlet 对象后,就调用此方法来初始化 Servlet 对象
    public void init(ServletConfig config) throws ServletException;
 
   //负责处理客户的请求并返回响应。当容器接收到客户端要求访问特定的 servlet 请求时,就会调用 Servlet 的 service 方法
   public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
 
   //Destroy()方法负责释放 Servlet 对象占用的资源,当 servlet 对象结束生命周期时,servlet 容器调用此方法来销毁 servlet 对象.
   public void destroy();
 
   //说明:Init(),service(),destroy() 这三个方法是 Servlet 生命周期中的最重要的三个方法。
   //返回一个字符串,在该字符串中包含 servlet 的创建者,版本和版权等信息
    public String getServletInfo();
 
   //GetServletConfig: 返回一个 ServletConfig 对象,该对象中包含了 Servlet 初始化参数信息
    public ServletConfig getServletConfig();
}
init 方法接收一个 ServletConfig 参数,由容器传入.ServletConfig 就是 Servlet 的配置,在web.xml 中定义 Servlet 时通过 init-param 标签配置的参数由 ServletConfig 保存
 
 
 
 
ServletConfig 接口
public interface ServletConfig {
     //用于获取 Servlet 名,web.xml 中定义的 servlet-name
     String getServletName();
 
     //获取 Servlet 上下文对象(非常重要)
     ServletContext getServletContext();
 
     //获取 init-param 中的配置参数
     String getInitParameter(String var1);
 
     //获取配置的所有 init-param 名字集合
      Enumeration<String> getInitParameterNames();
}
ServletConfig 是 Servlet 级别,而 ServletContext 是全局的
 
 
 
 
GenericServlet 抽象类
GenericServlet 是 Servlet 的默认实现,是与具体协议无关的
//抽象类 GenericServlet 实现了 Servlet 接口的同时,也实现了 ServletConfig 接口和Serializable 这两个接口
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {
 
  //私有变量,保存 init()传入的 ServletConfig 对象的引用
  private transient ServletConfig config;
 
  //无参的构造方法
  public GenericServlet() { }
 
------------------------------------
以下方法实现了 servlet 接口中的 5 个方法
实现 Servlet 接口方法开始
------------------------------------
/*
实 现 接 口 Servlet 中 的 带 参 数 的 init(ServletConfig Config) 方 法 , 将 传 递 的
ServletConfig 对象的引用保存到私有成员变量中,
使得 GenericServlet 对象和一个 ServletConfig 对象关联.
同时它也调用了自身的不带参数的 init()方法**/
 
public void init(ServletConfig config) throws ServletException {
       this.config = config;
       this.init(); //调用了无参的 init()方法
}
 
//无参的 init()方法
public void init() throws ServletException {}
 
//空实现了 destroy 方法
public void destroy() { }
 
//实现了接口中的 getServletConfig 方法,返回 ServletConfig 对象
public ServletConfig getServletConfig(){
    return config;
}
 
//该方法实现接口<Servlet>中的 ServletInfo,默认返回空字符串
public String getServletInfo() {
      return "";
}
 
//唯一没有实现的抽象方法 service(),仅仅在此声明。交由子类去实现具体的应用
//在后来的 HttpServlet 抽象类中,针对当前基于 Http 协议的 Web 开发,HttpServlet抽象类具体实现了这个方法
//若有其他的协议,直接继承本类后实现相关协议即可,具有很强的扩展性
public abstract void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
 
------------------------------------
实现 Servlet 接口方法结束
------------------------------------
---------------------------------------------
以下四个方法实现了接口 ServletConfig 中的方法
实现 ServletConfig 接口开始
---------------------------------------------
// 该方法实现了接口<ServletConfig>中的getServletContext方法 ,用于返 回servleConfig 对象中所包含的 servletContext 方法
public ServletContext getServletContext() {
     return getServletConfig().getServletContext();
}
 
//获取初始化参数
public String getInitParameter(String name) {
      return getServletConfig().getInitParameter(name);
}
 
//实现了接口<ServletConfig>中的方法,用于返回在 web.xml 文件中为 servlet 所配置的全部的初始化参数的值
public Enumeration getInitParameterNames() {
     return getServletConfig().getInitParameterNames();
 
   //获取在 web.xml 文件中注册的当前的这个 servlet 名称。没有在 web.xml 中注册的 servlet,该方法直接放回该 servlet 的类名。
   //法实现了接口<ServleConfig>中的 getServletName 方法
public String getServletName() {
     return config.getServletName();
}
 
---------------------------------------------
实现 ServletConfig 接口结束
---------------------------------------------
public void log(String msg) {
      getServletContext().log(getServletName() + ": "+ msg);
}
public void log(String message, Throwable t) {
      getServletContext().log(getServletName() + ": " + message, t);
}
}
 
 
基于协议的 HttpServlet
     HttpServlet 是基于 Http 协议实现的 Servlet 基类,我们在写 Servlet 的时候直接继承它就行了.SpringMVC 中的 DispatchServlet 就是继承了 HttpServlet.HttpServlet 重新了 service 方法, 而 service 方 法 首 先 将 ServletRequest 和 ServletResponse 转 成 HttpServletRequest和HttpServletResponse,然后根据 Http 不同类型的请求,再路由到不同的处理方法进行处理
 
 
 
 
Tomcat 源码分析
 
 
Tomcat 架构图
 
 
 
 
 
 
Server
Server 服务器的意思,代表整个 tomcat 服务器,一个 tomcat 只有一个 Server
Server 中包含至少一个 Service 组件,用于提供具体服务。这个在配置文件中也得到很好的体现(port=“8005” shutdown="SHUTDOWN"是在 8005 端口监听到"SHUTDOWN"命令,服务器就会停止)
 
 
Service
Service 中的一个逻辑功能层, 一个 Server 可以包含多个 Service
Service 接收客户端的请求,然后解析请求,完成相应的业务逻辑,然后把处理后的结果返回给客户端,一般会提供两个方法,一个 start 打开服务 Socket 连接,监听服务端口, 一个 stop 停止服务释放网络资源。
 
 
 
 
Connector
 
称作连接器,是 Service 的核心组件之一,一个 Service 可以有多个 Connector,主要是连接客户端请求,用于接受请求并将请求封装成 Request 和 Response,然后交给 Container 进行处理,Container 处理完之后在交给 Connector 返回给客户端。
 
 
 
Container
Service 的另一个核心组件,按照层级有 Engine,Host,Context,Wrapper 四种,一个Service 只有一个 Engine,其主要作用是执行业务逻辑
 
 
Engine
一个 Service 中有多个 Connector 和一个 Engine,Engine 表示整个 Servlet 引擎,一个Engine 下面可以包含一个或者多个 Host,即一个 Tomcat 实例可以配置多个虚拟主机,默认的情况下 conf/server.xml 配置文件中<Engine name="Catalina" defaultHost="localhost"> 定义了一个名为 Catalina 的 Engine。
一个 Engine 包含多个 Host 的设计,使得一个服务器实例可以承担多个域名的服务
 
 
Host
代表一个站点,也可以叫虚拟主机,一个 Host 可以配置多个 Context,在 server.xml 文件 中 的 默 认 配 置 为 <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">,
其中 appBase=webapps, 也就是<CATALINA_HOME>\webapps 目录,
unpackingWARS=true 属 性 指 定 在 appBase 指 定 的 目 录 中 的 war 包 都 自 动 的 解 压 ,
autoDeploy=true 属性指定对加入到 appBase 目录的 war 包进行自动的部署。
 
 
Context
 
Context,代表一个应用程序,就是日常开发中的web程序,或者一个WEB-INF目录以及下面的web.xml文件,换句话说每一个运行的 webapp 最终都是以 Context 的形式存在,每个 Context 都有一个根路径和请求路径;与 Host 的区别是 Context 代表一个应用,如默认配置下 webapps 下的每个目录都是一个应用,其中 ROOT 目录中存放主应用,其他目录存放别的子应用,而整个 webapps 是一个站点。
 
 
 
 
 
Tomcat 启动源码分析
 
启动流程
tomcat 的启动流程很标准化,入口是 BootStrap,统一按照生命周期管理接口 Lifecycle的定义进行启动。首先,调用 init()方法逐级初始化,接着调用 start()方法进行启动,同时, 每次调用伴随着生命周期状态变更事件的触发。
 
 
 
 
 
Startup.bat
其中最主要的里面有设置
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
 
 
catalina.bat
set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar"
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
 
Bootstrap
main 方法是整个 tomcat 启动时的入口。在 main 方法中,使用 bootstrap.init()来初始化类加载器和创建 Catalina 实例,然后再启动 Catalina 线程
 
bootstrap.init()方法
用 于 初 始 化 容 器 相 关 , 首 先 创 建 类 加 载 器 , 然 后 通 过 反 射 创 建org.apache.catalina.startup.Catalina 实例。
 
 
 
Catalina
Lifecycle 接口
Lifecycle 提供一种统一的管理对象生命周期的接口。通过 Lifecycle、LifecycleListener、LifecycleEvent,Catalina 实现了对 tomcat 各种组件、容器统一的启动和停止的方式。
在 Tomcat 服 务 开 启 过 程 中 启 动 的 一 些 列 组 件 、 容 器 , 都 实 现 了org.apache.catalina.Lifecycle 这个接口,其中的 init()、start() 方法、stop() 方法,为其子类实现了统一的 start 和 stop 管理
 
 
load 方法解析 server.xml 配置文件
load 方法解析 server.xml 配置文件,并加载 Server、Service、Connector、Container、Engine、Host、Context、Wrapper 一系列的容器。加载完成后,调用 initialize()来开启一个新的 Server
 
 
Digester 类解析 server.xml 文件
利用 Digester 类解析 server.xml 文件,得到容器的配置。
 
 
demon.start()
demon.start()方法会调用 Catalina 的 start 方法
Catalina 实例执行 start 方法。这里有两个点,一个是 load()加载 server.xml 配置、初始化 Server 的过程,一个是 getServer().start()开启服务、初始化并开启一系列组件、子容器的过程
 
 
 
StandardServer
service.initialize()

然后拿到 StandardServer 实例调用 initialize()方法初始化 Tomcat 容器的一系列组件。一些容器初始化的的时候,都会调用其子容器的 initialize()方法,初始化它的子容器。顺序是StandardServer、StandardService、StandardEngine、Connector。每个容器都在初始化自身相关设置的同时,将子容器初始化。

Servlet和Tomcat底层源码分析的更多相关文章

  1. List-LinkedList、set集合基础增强底层源码分析

    List-LinkedList 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 继上一章继续讲解,上章内容: List-ArreyLlist集合基础增强底层源码分析:https:// ...

  2. List-ArrayList集合基础增强底层源码分析

    List集合基础增强底层源码分析 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 集合分为三个系列,分别为:List.set.map List系列 特点:元素有序可重复 有序指的是元素的 ...

  3. LInkedList总结及部分底层源码分析

    LInkedList总结及部分底层源码分析 1. LinkedList的实现与继承关系 继承:AbstractSequentialList 抽象类 实现:List 接口 实现:Deque 接口 实现: ...

  4. Vector总结及部分底层源码分析

    Vector总结及部分底层源码分析 1. Vector继承的抽象类和实现的接口 Vector类实现的接口 List接口:里面定义了List集合的基本接口,Vector进行了实现 RandomAcces ...

  5. JAVA ArrayList集合底层源码分析

    目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ...

  6. JavaWeb过滤器Filter(附tomcat部分源码分析)

    过滤器Filter 过滤器通常对一些web资源进行拦截,做完一些处理器再交给下一个过滤器处理,直到所有的过滤器处理器,再调用servlet实例的service方法进行处理.过滤器可以对request进 ...

  7. 分布式缓存技术之Redis_Redis集群连接及底层源码分析

    目录 1. Jedis 单点连接 2. Jedis 基于sentinel连接 基本使用 源码分析 本次源码分析基于: jedis-3.0.1 1. Jedis 单点连接   当是单点服务时,Java ...

  8. 持久层Mybatis3底层源码分析,原理解析

    Mybatis-持久层的框架,功能是非常强大的,对于移动互联网的高并发 和 高性能是非常有利的,相对于Hibernate全自动的ORM框架,Mybatis简单,易于学习,sql编写在xml文件中,和代 ...

  9. Java——HashMap底层源码分析

    1.简介 HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的. HashMap 最多只允许一条记录的key为 nu ...

随机推荐

  1. 转载]OK6410之tftp下载内核,nfs挂载文件系统全过程详解[转]

    原文地址:OK6410之tftp下载内核,nfs挂载文件系统全过程详解[转]作者:千山我独行 由于工作的平台也是嵌入式,差不多的平台,所以一直就没有把自己买过来的ok6410板子好好玩玩.以前一直都是 ...

  2. 2019年10月13日 linux习题 wangqingchao

    1. GUN的含义是: GNU's Not UNIX . 2. Linux一般有3个主要部分:内核.命令解释层.实用工具. 3.POSIX是可携式操作系统接口的缩写,重点在规范核心与应用程序之间的接口 ...

  3. Elasticsearch系列---Elasticsearch的基本概念及工作原理

    基本概念 Elasticsearch有几个核心的概念,花几分钟时间了解一下,有助于后面章节的学习. NRT Near Realtime,近实时,有两个层面的含义,一是从写入一条数据到这条数据可以被搜索 ...

  4. PHP代码安全有必要了解下

    攻击者通过构造恶意SQL命令发送到数据库,如果程序未对用户输入的 SQL命令执行判断过滤,那么生成的SQL语句可能会绕过安全性检查,插入其他用于修改后端数据库的语句,并可能执行系统命令,从而对系统造成 ...

  5. PHP 向数组头部插入数据

    PHP 向数组头部插入数据 函数: array_unshift() 示例: $s = array('a' => 0, 'b' => 3); array_unshift($s, '5'); ...

  6. nyoj 35-表达式求值(stack, 栈的应用)

    35-表达式求值 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:37 submit:53 题目描述: ACM队的mdd想做一个计算器,但是,他要做的 ...

  7. 在 Windows 上 安装 Oracle 11g Xe

    去oracle官网下载 https://www.oracle.com/database/technologies/xe-prior-releases.html 点击下载: Oracle Databas ...

  8. ACE框架 基于共享内存的分配器 (算法设计)

    继承上一篇<ACE框架 基于共享内存的分配器设计>,本篇分析算法部分的设计. ACE_Malloc_T模板定义了这样一个分配器组件 分配器组件聚合了三个功能组件:同步组件ACE_LOCK, ...

  9. RevitAPI 隐藏UI读取Revit文件

    1.1. 新建一个控制台项目 1.2. 添加Revit API引用 我们找到revit安装目录下的这两个DLL添加到项目引用中 RevitNET.dll RevitAPI.dll 修改属性:复制本地: ...

  10. Error: invalid "instanceof" keyword value Promise的解决方法

    执行npm run dev 时,发现错误 Error: invalid "instanceof" keyword value Promise 经过一番查找,发现原因是webpack ...