> 文章列表 > (三)Tomcat源码阅读:Server组件分析

(三)Tomcat源码阅读:Server组件分析

(三)Tomcat源码阅读:Server组件分析

一、概述

打开tomcat源码找到server类,我们可以从开头的注释获取一些主要信息。

我对下面的注释进行概述:Server是顶级元素,并且实现了Lifecycle接口,例如start和stop方法

/* A <code>Server</code> element represents the entire Catalina* servlet container.  Its attributes represent the characteristics of* the servlet container as a whole.  A <code>Server</code> may contain* one or more <code>Services</code>, and the top level set of naming* resources.* <p>* Normally, an implementation of this interface will also implement* <code>Lifecycle</code>, such that when the <code>start()</code> and* <code>stop()</code> methods are called, all of the defined* <code>Services</code> are also started or stopped.* <p>* In between, the implementation must open a server socket on the port number* specified by the <code>port</code> property.  When a connection is accepted,* the first line is read and compared with the specified shutdown command.* If the command matches, shutdown of the server is initiated.* <p>* <strong>NOTE</strong> - The concrete implementation of this class should* register the (singleton) instance with the <code>ServerFactory</code>* class in its constructor(s). @author Craig R. McClanahan*/

二、阅读源码

源码阅读中,我的一般顺序是这样:接口->抽象类->实现类(子类)。因为位于比较高级的类,越能对项目进行概览,并能从大到小对项目进行分析,不容易掉进牛角尖。当然具体的过程还要具体分析,不一定死套这个顺序。接下我们就按照Lifecycle->Server->StandardServer的顺序进行阅读。

 (一)Lifecycle

1、类注释

Lifecycle这个类为容器定义了统一的生命周期的方法,例如:启动,停止等。下面的图片表明了声明周期之间相互转化的流程。也就是所有容器都实现了生命周期的方法。

/* Common interface for component life cycle methods.  Catalina components* may implement this interface (as well as the appropriate interface(s) for* the functionality they support) in order to provide a consistent mechanism* to start and stop the component.* <br>* The valid state transitions for components that support {@link Lifecycle}* are:* <pre>*            start()*  -----------------------------*  |                           |*  | init()                    |* NEW -»-- INITIALIZING        |* | |           |              |     ------------------«-----------------------* | |           |auto          |     |                                        |* | |          \\|/    start() \\|/   \\|/     auto          auto         stop() |* | |      INITIALIZED --»-- STARTING_PREP --»- STARTING --»- STARTED --»---  |* | |         |                                                            |  |* | |destroy()|                                                            |  |* | --»-----«--    ------------------------«--------------------------------  ^* |     |          |                                                          |* |     |         \\|/          auto                 auto              start() |* |     |     STOPPING_PREP ----»---- STOPPING ------»----- STOPPED -----»-----* |    \\|/                               ^                     |  ^* |     |               stop()           |                     |  |* |     |       --------------------------                     |  |* |     |       |                                              |  |* |     |       |    destroy()                       destroy() |  |* |     |    FAILED ----»------ DESTROYING ---«-----------------  |* |     |                        ^     |                          |* |     |     destroy()          |     |auto                      |* |     --------»-----------------    \\|/                         |* |                                 DESTROYED                     |* |                                                               |* |                            stop()                             |* ----»-----------------------------»------------------------------ Any state can transition to FAILED. Calling start() while a component is in states STARTING_PREP, STARTING or* STARTED has no effect. Calling start() while a component is in state NEW will cause init() to be* called immediately after the start() method is entered. Calling stop() while a component is in states STOPPING_PREP, STOPPING or* STOPPED has no effect. Calling stop() while a component is in state NEW transitions the component* to STOPPED. This is typically encountered when a component fails to start and* does not start all its sub-components. When the component is stopped, it will* try to stop all sub-components - even those it didn't start. Attempting any other transition will throw {@link LifecycleException}. </pre>* The {@link LifecycleEvent}s fired during state changes are defined in the* methods that trigger the changed. No {@link LifecycleEvent}s are fired if the* attempted transition is not valid. @author Craig R. McClanahan*/

2、常量

这里主要定义了生命周期中定义的一些常量,了解即可

// ----------------------------------------------------- Manifest Constants/* The LifecycleEvent type for the "component before init" event.*/String BEFORE_INIT_EVENT = "before_init";/* The LifecycleEvent type for the "component after init" event.*/String AFTER_INIT_EVENT = "after_init";/* The LifecycleEvent type for the "component start" event.*/String START_EVENT = "start";/* The LifecycleEvent type for the "component before start" event.*/String BEFORE_START_EVENT = "before_start";/* The LifecycleEvent type for the "component after start" event.*/String AFTER_START_EVENT = "after_start";/* The LifecycleEvent type for the "component stop" event.*/String STOP_EVENT = "stop";/* The LifecycleEvent type for the "component before stop" event.*/String BEFORE_STOP_EVENT = "before_stop";/* The LifecycleEvent type for the "component after stop" event.*/String AFTER_STOP_EVENT = "after_stop";/* The LifecycleEvent type for the "component after destroy" event.*/String AFTER_DESTROY_EVENT = "after_destroy";/* The LifecycleEvent type for the "component before destroy" event.*/String BEFORE_DESTROY_EVENT = "before_destroy";/* The LifecycleEvent type for the "periodic" event.*/String PERIODIC_EVENT = "periodic";/* The LifecycleEvent type for the "configure_start" event. Used by those* components that use a separate component to perform configuration and* need to signal when configuration should be performed - usually after* {@link #BEFORE_START_EVENT} and before {@link #START_EVENT}.*/String CONFIGURE_START_EVENT = "configure_start";/* The LifecycleEvent type for the "configure_stop" event. Used by those* components that use a separate component to perform configuration and* need to signal when de-configuration should be performed - usually after* {@link #STOP_EVENT} and before {@link #AFTER_STOP_EVENT}.*/String CONFIGURE_STOP_EVENT = "configure_stop";

不得不说tomcat中编码是比较规范的,在常量的地方标记常量,在方法的地方标记方法,这是我们要xue

3、方法

方法介绍中我们就忽略掉不太重要的方法找比较重要的方法进行介绍。下面这四个方法定义了容器从初始化到销毁的过程,为什么我会把它选为重要方法,因为开头的类注释就说明了,这个类的作用就是定义容器的生命周期,因此这四个对应生命周期的方法比较重要。

void init() throws LifecycleException;void start() throws LifecycleException;void stop() throws LifecycleException;void destroy() throws LifecycleException;

(二)Server

1、类注释

这部分主要说明了Server是整个tomcat组件的顶层,如果它停止了它下面的组件都会停止,并且它实现了生命周期。

/* A <code>Server</code> element represents the entire Catalina* servlet container.  Its attributes represent the characteristics of* the servlet container as a whole.  A <code>Server</code> may contain* one or more <code>Services</code>, and the top level set of naming* resources.* <p>* Normally, an implementation of this interface will also implement* <code>Lifecycle</code>, such that when the <code>start()</code> and* <code>stop()</code> methods are called, all of the defined* <code>Services</code> are also started or stopped.* <p>* In between, the implementation must open a server socket on the port number* specified by the <code>port</code> property.  When a connection is accepted,* the first line is read and compared with the specified shutdown command.* If the command matches, shutdown of the server is initiated.* <p>* <strong>NOTE</strong> - The concrete implementation of this class should* register the (singleton) instance with the <code>ServerFactory</code>* class in its constructor(s). @author Craig R. McClanahan*/

(三)StandardServer 

StandardServer继承了LifecycleMBeanBase类但是我们无需去深究LifecycleMBeanBase类,因为LifecycleMBeanBase是做监控用的,我们现在的任务是理清大概流程,因此不用深究LifecycleMBeanBase,只需要了解StandardServer即可。

1、主要方法

addService

    @Overridepublic void addService(Service service) {service.setServer(this);//加锁并通过动态数组的方式添加servicesynchronized (servicesLock) {Service results[] = new Service[services.length + 1];System.arraycopy(services, 0, results, 0, services.length);results[services.length] = service;services = results;if (getState().isAvailable()) {try {service.start();} catch (LifecycleException e) {// Ignore}}//将添加service的事件发给监听器support.firePropertyChange("service", null, service);}}
 @Overridepublic void removeService(Service service) {//加锁将对象移除synchronized (servicesLock) {int j = -1;for (int i = 0; i < services.length; i++) {if (service == services[i]) {j = i;break;}}if (j < 0) {return;}try {services[j].stop();} catch (LifecycleException e) {// Ignore}int k = 0;Service results[] = new Service[services.length - 1];for (int i = 0; i < services.length; i++) {if (i != j) {results[k++] = services[i];}}services = results;// 将事件发给监听器support.firePropertyChange("service", service, null);}}

下面这些方法是是server对service的管理,server通过这些方法将其下属的service进行初始化,启动,停止,销毁等操作。

    /* Start nested components ({@link Service}s) and implement the requirements of* {@link org.apache.catalina.util.LifecycleBase#startInternal()}. @exception LifecycleException if this component detects a fatal error that prevents this component from being*                                   used*/@Overrideprotected void startInternal() throws LifecycleException {fireLifecycleEvent(CONFIGURE_START_EVENT, null);setState(LifecycleState.STARTING);globalNamingResources.start();// Start our defined Servicessynchronized (servicesLock) {for (Service service : services) {service.start();}}}/* Stop nested components ({@link Service}s) and implement the requirements of* {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. @exception LifecycleException if this component detects a fatal error that needs to be reported*/@Overrideprotected void stopInternal() throws LifecycleException {setState(LifecycleState.STOPPING);fireLifecycleEvent(CONFIGURE_STOP_EVENT, null);// Stop our defined Servicesfor (Service service : services) {service.stop();}globalNamingResources.stop();stopAwait();}/* Invoke a pre-startup initialization. This is used to allow connectors to bind to restricted ports under Unix* operating environments.*/@Overrideprotected void initInternal() throws LifecycleException {super.initInternal();// Register global String cache// Note although the cache is global, if there are multiple Servers// present in the JVM (may happen when embedding) then the same cache// will be registered under multiple namesonameStringCache = register(new StringCache(), "type=StringCache");// Register the MBeanFactoryMBeanFactory factory = new MBeanFactory();factory.setContainer(this);onameMBeanFactory = register(factory, "type=MBeanFactory");// Register the naming resourcesglobalNamingResources.init();// Populate the extension validator with JARs from common and shared// class loadersif (getCatalina() != null) {ClassLoader cl = getCatalina().getParentClassLoader();// Walk the class loader hierarchy. Stop at the system class loader.// This will add the shared (if present) and common class loaderswhile (cl != null && cl != ClassLoader.getSystemClassLoader()) {if (cl instanceof URLClassLoader) {URL[] urls = ((URLClassLoader) cl).getURLs();for (URL url : urls) {if (url.getProtocol().equals("file")) {try {File f = new File(url.toURI());if (f.isFile() && f.getName().endsWith(".jar")) {ExtensionValidator.addSystemResource(f);}} catch (URISyntaxException | IOException e) {// Ignore}}}}cl = cl.getParent();}}// Initialize our defined Servicesfor (Service service : services) {service.init();}}@Overrideprotected void destroyInternal() throws LifecycleException {// Destroy our defined Servicesfor (Service service : services) {service.destroy();}globalNamingResources.destroy();unregister(onameMBeanFactory);unregister(onameStringCache);super.destroyInternal();}

三、思考点

为什么这里添加服务使用的锁是servicesLock而不是services数组?

    /* The set of Services associated with this Server.*/private Service services[] = new Service[0];private final Object servicesLock = new Object();@Overridepublic void addService(Service service) {service.setServer(this);//加锁并通过动态数组的方式添加servicesynchronized (servicesLock) {Service results[] = new Service[services.length + 1];System.arraycopy(services, 0, results, 0, services.length);results[services.length] = service;services = results;if (getState().isAvailable()) {try {service.start();} catch (LifecycleException e) {// Ignore}}//将添加service的事件发给监听器support.firePropertyChange("service", null, service);}}

我的思考是这样的如果锁住了数组的话,这个数组的读操作就被限制住了,如果别的数组想读的话还要等待,颗粒度太粗,因此使用一个final的对象作为锁锁住代码块,提升代码执行效率。

参考文章:

Server - 简书