[应用服务器]掌握Tomcat应用服务器只需一分钟

栏目: Java · 发布时间: 5年前

内容简介:进入tomcat官网:https://tomcat.apache.org/ 下载对应版本的源码

No.1 搭建环境

1.1、下载tomcat源码

进入tomcat官网:https://tomcat.apache.org/ 下载对应版本的源码

1.2、导入Eclipse

  • 新建一个 Java 项目
  • 将Tomcat源码包中的java目录下的文件拷贝到src目录
  • 导入外部依赖包
ant.jar 
ecj-4.4.jar 
jaxrpc.jar 
wsdl4j-1.5.2.jar 

[应用服务器]掌握Tomcat应用服务器只需一分钟

No.2 Tomcat顶层结构

[应用服务器]掌握Tomcat应用服务器只需一分钟

上图大概展示了tomcat的结构,主要包括如下几个模块:

  • Server:

服务器的意思,代表整个tomcat服务器,一个tomcat只有一个Server;

  • Service:

Server中的一个逻辑功能层,一个Server可以包含多个Service;

  • Connector:

称作连接器,是Service的核心组件之一,一个Service可以有多个Connector,主要是连接客户端请求;

  • Container:

Service的另一个核心组件,按照层级有Engine,Host,Context,Wrapper四种,一个Service只有一个Engine,其主要作用是执行业务逻辑;

  • Jasper:

JSP引擎;

  • Session:

会话管理;

No.3 Server

Server是Tomcat最顶层的容器,代表着整个服务器,即一个Tomcat只有一个Server,Server中包含至少一个Service组件,用于提供具体服务。

这个在配置文件中也得到很好的体现(port=”8005” shutdown=”SHUTDOWN”是在8005端口监听到”SHUTDOWN”命令,服务器就会停止)。

tomcat中定义了一个Server接口,其声明如下:

public interface Server extends Lifecycle { 

它继承了Lifecycle接口,这样当调用start()和stop()方法时,所有已定义的Services也会启动或停止。

  • 它的标准实现是:org.apache.catalina.core.StandardServer 类。
  • Server元素表示整个Catalina servlet容器。
  • 它的属性代表整个servlet容器的特征。
  • 服务器可能包含一个或多个服务,以及顶级命名资源集。
  • 它的具体实现应该在其构造函数中使用ServerFactory类注册(singleton)实例。

No.4 Service

前面我们讲过,一个Server至少包含一个Service组件来提供具体的服务。

那Service的基本功能大致是接收客户端的请求,然后解析请求,完成相应的业务逻辑,然后把处理后的结果返回给客户端。

一般会提供两个节本方法,一个start打开服务Socket连接,监听服务端口,一个stop停止服务释放网络资源。

tomcat中定义一个Service接口,其声明如下:

public interface Service extends Lifecycle { 
  • 一个Service是一组包含一个或多个Connectors,这些Connectors共享一个Container来处理请求。
  • Connector负责处理请求监听,Container负责处理请求处理
  • 从conf/server.xml文件的配置可以知道,Service相当于Connector和Engine组件的包装器,将一个或者多个Connector和一个Engine建立关联关系。在默认的配置文件中,定义了一个叫Catalina 的服务,它将HTTP/1.1和AJP/1.3这两个Connector与一个名为Catalina 的Engine关联起来。

一个Server可以包含多个Service(它们相互独立,只是公用一个JVM及类库),一个Service负责维护多个Connector和一个Container。

No.5 Connector

Connector是连接器,用于接受请求并将请求封装成Request和Response,然后交给Container进行处理,Container处理完之后在交给Connector返回给客户端。

server.xml默认配置了两个Connector:

  • 监听端口8080,这个端口值可以修改,connectionTimeout定义了连接超时时间,单位是毫秒,redirectPort 定义了ssl的重定向接口,根据上述配置,Connector会将ssl请求转发到8443端口。
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/> 
  • 监听端口8009,AJP表示Apache Jserv Protocol,它将处理Tomcat和Apache http服务器之间的交互,此连接器用于处理我们将Tomcat和Apache http服务器结合使用的情况,如在同一台物理Server上部署一个Apache http服务器和多台Tomcat服务器,通过Apache服务器来处理静态资源以及负载均衡时,针对不同的Tomcat实例需要AJP监听不同的端口。
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> 

Connector在tomcat中的设计大致如下:

[应用服务器]掌握Tomcat应用服务器只需一分钟

  • Connector使用ProtocolHandler来处理请求的,不同的ProtocolHandler代表不同的连接类型
  • ProtocolHandler由包含了三个部件:Endpoint、Processor、Adapter

Endpoint由于是处理底层的Socket网络连接,因此Endpoint是用来实现TCP/IP协议的

Processor用于将Endpoint接收到的Socket封装成Request,Processor用来实现HTTP协议的

Adapter充当适配器,用于将Request转换为ServletRequest交给Container进行具体的处理

No.6 Container

Container 用于封装和管理 Servlet,以及具体处理 Request 请求,在Container内部包含了4个子容器,4个子容器的作用分别是:

  • Engine:

引擎,用来管理多个站点,一个Service最多只能有一个Engine;

  • Host:

代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点;

  • Context:

代表一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件;

  • Wrapper:

每一Wrapper封装着一个Servlet;

[应用服务器]掌握Tomcat应用服务器只需一分钟

No.7 tomcat启动流程

tomcat的启动流程很标准化,入口是BootStrap,统一按照生命周期管理接口Lifecycle的定义进行启动。

首先,调用init()方法逐级初始化,接着调用start()方法进行启动,同时,每次调用伴随着生命周期状态变更事件的触发。

  • org.apache.catalina.startup.Bootstrap的程序入口main方法,具体实现如下:
public static void main(String args[]) { 
 
        if (daemon == null) { 
            // Don't set daemon until init() has completed 
            Bootstrap bootstrap = new Bootstrap(); 
            try { 
                bootstrap.init(); 
            } catch (Throwable t) { 
                handleThrowable(t); 
                t.printStackTrace(); 
                return; 
            } 
            daemon = bootstrap; 
        } else { 
            // When running as a service the call to stop will be on a new 
            // thread so make sure the correct class loader is used to prevent 
            // a range of class not found exceptions. 
            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); 
        } 
 
        try { 
            String command = "start"; 
            if (args.length > 0) { 
                command = args[args.length - 1]; 
            } 
 
            if (command.equals("startd")) { 
                args[args.length - 1] = "start"; 
                daemon.load(args); 
                daemon.start(); 
            } else if (command.equals("stopd")) { 
                args[args.length - 1] = "stop"; 
                daemon.stop(); 
            } else if (command.equals("start")) { 
                daemon.setAwait(true); 
                daemon.load(args); 
                daemon.start(); 
            } else if (command.equals("stop")) { 
                daemon.stopServer(args); 
            } else if (command.equals("configtest")) { 
                daemon.load(args); 
                if (null==daemon.getServer()) { 
                    System.exit(1); 
                } 
                System.exit(0); 
            } else { 
                log.warn("Bootstrap: command \"" + command + "\" does not exist."); 
            } 
        } catch (Throwable t) { 
            // Unwrap the Exception for clearer error reporting 
            if (t instanceof InvocationTargetException && 
                    t.getCause() != null) { 
                t = t.getCause(); 
            } 
            handleThrowable(t); 
            t.printStackTrace(); 
            System.exit(1); 
        } 
 
} 
  • org.apache.catalina.startup.Bootstrap的初始化方法,具体实现如下:
public void init() throws Exception  { 
        // 1、设置catalina.home的配置:将catalina.home系统属性设置为当前工作目录(如果尚未设置)。 
        setCatalinaHome(); 
    // 2、设置catalina.base的配置:如果没有设置的话,将当前的工作目录为了catalina.base的设置 
        setCatalinaBase(); 
    // 3、初始化类加载器:commonLoader、catalinaLoader、sharedLoader 
        initClassLoaders(); 
 
        Thread.currentThread().setContextClassLoader(catalinaLoader); 
 
        SecurityClassLoad.securityClassLoad(catalinaLoader); 
 
        // 加载我们的启动类并调用其process()方法 
        if (log.isDebugEnabled()) 
            log.debug("Loading startup class"); 
    //4、加载启动类 
        Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); 
        //5、实例化启动类 
    Object startupInstance = startupClass.newInstance(); 
 
        if (log.isDebugEnabled()) 
            log.debug("Setting startup class properties"); 
 
    //6、设置方法参数 
    String methodName = "setParentClassLoader"; 
        Class<?> paramTypes[] = new Class[1]; 
        paramTypes[0] = Class.forName("java.lang.ClassLoader"); 
        Object paramValues[] = new Object[1]; 
        paramValues[0] = sharedLoader; 
        Method method = startupInstance.getClass().getMethod(methodName, paramTypes); 
    // 7、调用启动类的setParentClassLoader方法设置共享扩展类加载器 
        method.invoke(startupInstance, paramValues); 
 
        catalinaDaemon = startupInstance; 
 
} 
  • org.apache.catalina.startup.Bootstrap的start()方法,具体实现如下:
/** 
* Start the Catalina daemon. 
*/ 
public void start() throws Exception { 
    // 如果启动类为实例化,则调用init()方法 
    if( catalinaDaemon==null ) init(); 
 
    //获取启动类的start方法 
    Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null); 
    //调用启动类的start方法,即调用org.apache.catalina.startup.Catalina的start()方法 
    method.invoke(catalinaDaemon, (Object [])null); 
 
} 

具体时序图如下:

[应用服务器]掌握Tomcat应用服务器只需一分钟

总结

整个Tomcat从代码的角度来看,就是这样的:

[应用服务器]掌握Tomcat应用服务器只需一分钟

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learning Vue.js 2

Learning Vue.js 2

Olga Filipova / Packt Publishing / 2017-1-5 / USD 41.99

About This Book Learn how to propagate DOM changes across the website without writing extensive jQuery callbacks code.Learn how to achieve reactivity and easily compose views with Vue.js and unders......一起来看看 《Learning Vue.js 2》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

html转js在线工具
html转js在线工具

html转js在线工具