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

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

No.1 搭建环境

1.1、下载tomcat源码

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

1.2、导入Eclipse

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

[[252191]]

No.2 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接口,其声明如下:

  1. 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接口,其声明如下:

  1. 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端口。
  1. <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监听不同的端口。
  1. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> 

Connector在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;

 


No.7 tomcat启动流程

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

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

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

具体时序图如下:

总结

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


责任编辑:武晓燕 来源: 爱折腾的稻草
相关推荐

2009-01-16 14:37:57

TomcatWeb服务器应用服务器

2009-01-10 19:32:36

2019-10-23 10:14:24

TomcatJettyGlassFish

2012-02-02 10:24:08

JavaResin

2009-06-16 15:35:20

JBoss应用服务器

2021-05-28 05:18:08

PHP语言roadrunnner

2009-02-27 14:25:00

Weblogic应用服务器服务器管理

2012-02-23 10:02:08

Web服务器应用服务器

2011-08-05 09:37:45

2009-06-16 12:02:37

JBoss IPv6

2009-05-08 16:38:54

SpringHyperic服务器

2009-06-18 10:03:57

EquinoxOSGi应用服务器

2018-02-07 10:08:02

应用服务器网络数据库

2014-08-08 16:35:37

应用服务器

2018-05-24 10:15:18

服务器Session问题

2012-03-23 09:32:48

应用服务器

2018-03-20 14:24:10

Web服务器HTTP

2017-10-17 09:15:06

Web服务器区别

2019-07-17 15:05:35

应用服务器Tomcat监控
点赞
收藏

51CTO技术栈公众号