`
uule
  • 浏览: 6348925 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

StandardServer分析-tomcat6.x源码阅读

 
阅读更多

来源:https://my.oschina.net/douglas/blog/161029

 

StandardServer是什么

StandardServer标准实现Server接口,从tomcat结构层次图中知道,Server处于最外层,其他组件在其内部,起统领做,像一家公司的CEO,负责管理整个公司,Server代表完整的Servlet容器,管理维护Server和全局resource,在各个组件中共享StandardServer资源。在tomcat启动过程中由Catalina通过Digester库加载解析server.xml,创建StandardServer对象,并初始化和启动Server,Server将自己注册到JMX上面,通过tomcat管理页面查看Server状态。StandardServer除了实现Server接口以外,还使用下列组件来完成功能。

Lifecycle StandardServer实现Lifecycle接口,Lifecycle是tomcat中关于组件生命周期状态监控操作监听的接口,通过Lifecycle提供的9个状态和5个方法,使得监控组件的状态更新和在组件不同生命周期阶段操作成为可能。
9的状态:指示组件状态

  • BEFORE_INIT
  • AFTER_INIT
  • BEFORE_START
  • START
  • AFTER_START
  • BEFORE_STOP
  • STOP
  • AFTER_STOP
  • BEFORE_DESTROY
  • AFTER_DESTROY
  • PERIODIC
  • CONFIG_START
  • CONFIG_STOP

5个方法: 更新组件状态和添加监听组件状态变更通知组件

  • addLifecycleListener(LifecycleListener)
  • findLifecycleListeners()
  • removeLifecycleListener(LifecycleListener)
  • start()
  • stop()

addLifecycleListener(LifecycleListener)是注册LifecycleEvent事件监听器。LifecycleListener是监听Lifecycle组件状态变更触发的LifecycleEvent事件,当LifecycleListener监听到LifecycleEvent事件事件时,会调用LifecycleListener方法lifecycleEvent(LifecycleEvent)响应事件。

MBeanRegistration
StandardServer实现MBeanRegistration接口。MBeanRegistration接口是JMX的MBean方法的内容,实现该接口的目的是将StandardServer组件注册到JMX中,通过JMX可以实现对StandardServer的控制。

LifecycleSupport
StandardServer的属性,它的作用就是负责管理Lifecycle接口实现类的LifecycleListener,只有一个到参的构造器,必须在创建对象时传入Lifecycle,在StandardServer中创建对象时同时将StandardServer自身传入,
private LifecycleSupport lifecycle = new LifecycleSupport(this);
LifecycleSupport 管理注册在StandardServer上的监听器,当监听到LifecycleEvent,LifecycleSupport 马上调用方法fireLifecycleEvent(String, Object)遍历监听器响应事件,属性state指明了当前Lifecycle的状态。

javax.naming.Context
StandardServer的属性,是JNDI中的内容,不了解,只知道它提供命名服务,也就是根据名字获取对象以及对象属性信息等,通过给定资源路径,然后就可以获取资源路径下面对象,在server.xml中关于资源的配置,从配置信息中可以看到配置的是tomcat管理页面登陆账号权限信息。

<!-- Global JNDI resources Documentation at /docs/jndi-resources-howto.html -->
    <GlobalNamingResources>
        <!-- Editable user database that can also be used by UserDatabaseRealm 
            to authenticate users -->
        <Resourcename="UserDatabase"auth="Container"type="org.apache.catalina.UserDatabase"description="User database that can be updated and saved"factory="org.apache.catalina.users.MemoryUserDatabaseFactory"pathname="conf/tomcat-users.xml" />
    </GlobalNamingResources>

 

java和第三方交互时经常使用,例如数据库驱动,mysql的JDBC和ODBC,java不用关心其实现部分。JNDI理解例子,来自博客lujin55

NamingContextListener
StandardServer的属性,是JNDI中的内容,不了解,比较复杂,只知道是负责监听javax.naming.Context资源事件。NamingContextListener实现了LifecycleListener、ContainerListener、PropertyChangeListener3个接口,具备监听Lifecycle组件,Container组件、PropertyChange的事件能力。

NamingResources
StandardServer的属性,是JNDI中的内容,不了解,比较复杂,知道它管理命名资源,将要加载的资源封装成对象,可以直接从NamingResources获取对象了。

PropertyChangeSupport
StandardServer的属性,参照LifecycleSupport的理解不难看出,PropertyChangeSupport管理对象属性变化监听器,跟LifecycleSupport的使命一样,监听PropertyChangeEvent事件,然后响应。

StandardServer通过JNDI加载server.xml中配置的资源,完成资源配置,注册监听器来监听事件,同时将自己注册到ServerFactory 上。StandardServer再次完成资源加载后调用init()方法初始化,实践调用的是initialize(),在tomcat启动中,调用初始化方法是由Catalina来完成。在initialize()方法中分4步完成

  • 第一步首先判断是否已经初始化
  • 第二部触发INIT_EVENT事件,标记已经初始化(initialized = true)
  • 第三步注册到MBeanServer服务器,添加监控,可以在tomcat管理页面管理Server
  • 第四步遍历services数组,挨个调用initialize()初始化
  • /**
         * Invoke a pre-startup initialization. This is used to allow connectors to
         * bind to restricted ports under Unix operating environments.
         */
        publicvoidinitialize()throws LifecycleException {
            if (initialized) {
                log.info(sm.getString("standardServer.initialize.initialized"));
                return;
            }
            lifecycle.fireLifecycleEvent(INIT_EVENT, null);
            initialized = true;
    
            if (oname == null) {
                try {
                    oname = new ObjectName("Catalina:type=Server");
                    Registry.getRegistry(null, null).registerComponent(this, oname,
                            null);
                } catch (Exception e) {
                    log.error("Error registering ", e);
                }
            }
    
            // Register global String cache
            try {
                ObjectName oname2 = new ObjectName(oname.getDomain()
                        + ":type=StringCache");
                Registry.getRegistry(null, null).registerComponent(
                        new StringCache(), oname2, null);
            } catch (Exception e) {
                log.error("Error registering ", e);
            }
    
            // Initialize our defined Services
            for (int i = 0; i < services.length; i++) {
                services[i].initialize();
            }
        }
     
  • StandardServer初始化完成后,调用start()方法启动Server,在start()方法分4步完成
  • 第一步首先判断Server是否已经启动
  • 第二部触发BEFORE_START_EVENT,START_EVENT事件,标记已经启动(started = true)
  • 第三步遍历services数组,挨个调用start()初始化
  • 第四步触发AFTER_START_EVENT事件,通知监听器
  • /**
         * Prepare for the beginning of active use of the public methods of this
         * component. This method should be called before any of the public methods
         * of this component are utilized. It should also send a LifecycleEvent of
         * type START_EVENT to any registered listeners.
         * 
         * @exception LifecycleException
         *                if this component detects a fatal error that prevents this
         *                component from being used
         */
        publicvoidstart()throws LifecycleException {
    
            // Validate and update our current component state
            if (started) {
                log.debug(sm.getString("standardServer.start.started"));
                return;
            }
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
    
            lifecycle.fireLifecycleEvent(START_EVENT, null);
            started = true;
    
            // Start our defined Services
            synchronized (services) {//同步
                for (int i = 0; i < services.length; i++) {
                    if (services[i] instanceof Lifecycle)
                        ((Lifecycle) services[i]).start();
                    System.out.println(i+":"+services[i].hashCode());//自己加的,为了验证catalina是否在Server的services列表中,最后事实证明catalina不在列表中
                }
            }
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
    
        }
  • StandardServer完成启动后,Catalina在start()方法中调用await()方法,await()中调用StandardServer的await(),StandardServer的await()方法主要完成的功能非常简单:启动ServerSocket监听网络端口请求关闭Server的请求,从代码中可以看出StandardServer使用一个死循环不断监听端口,当接收到"SHUTDOWN"命令时跳出循环,回到Catalina的start()方法中。
  • /**
         * Wait until a proper shutdown command is received, then return. This keeps
         * the main thread alive - the thread pool listening for http connections is
         * daemon threads.
         */
        public void await() {
            // Negative values - don't wait on port - tomcat is embedded or we just
            // don't like ports
            if (port == -2) {
                // undocumented yet - for embedding apps that are around, alive.
                return;
            }
            if (port == -1) {
                try {
                    awaitThread = Thread.currentThread();//当前线程
                    while (!stopAwait) {
                        try {
                            Thread.sleep(10000);
                        } catch (InterruptedException ex) {
                            // continue and check the flag
                        }
                    }
                } finally {
                    awaitThread = null;
                }
                return;
            }
    
            // Set up a server socket to wait on
            try {
                awaitSocket = new ServerSocket(port, 1,
                        InetAddress.getByName("localhost"));
            } catch (IOException e) {
                log.error("StandardServer.await: create[" + port + "]: ", e);
                return;
            }
    
            try {
                awaitThread = Thread.currentThread();//当前线程
    
                // Loop waiting for a connection and a valid command
                while (!stopAwait) {
                    ServerSocket serverSocket = awaitSocket;
                    if (serverSocket == null) {
                        break;
                    }
    
                    // Wait for the next connection
                    Socket socket = null;
                    StringBuilder command = new StringBuilder();
                    try {
                        InputStream stream = null;
                        try {
                            socket = serverSocket.accept();
                            socket.setSoTimeout(10 * 1000); // Ten seconds
                            stream = socket.getInputStream();
                        } catch (AccessControlException ace) {
                            log.warn("StandardServer.accept security exception: "
                                    + ace.getMessage(), ace);
                            continue;
                        } catch (IOException e) {
                            if (stopAwait) {
                                // Wait was aborted with socket.close()
                                break;
                            }
                            log.error("StandardServer.await: accept: ", e);
                            break;
                        }
    
                        // Read a set of characters from the socket
                        int expected = 1024; // Cut off to avoid DoS attack
                        while (expected < shutdown.length()) {
                            if (random == null)
                                random = new Random();
                            expected += (random.nextInt() % 1024);
                        }
                        while (expected > 0) {
                            int ch = -1;
                            try {
                                ch = stream.read();
                            } catch (IOException e) {
                                log.warn("StandardServer.await: read: ", e);
                                ch = -1;
                            }
                            if (ch < 32) // Control character or EOF terminates loop
                                break;
                            command.append((char) ch);
                            expected--;
                        }
                    } finally {
                        // Close the socket now that we are done with it
                        try {
                            if (socket != null) {
                                socket.close();
                            }
                        } catch (IOException e) {
                            // Ignore
                        }
                    }
    
                    // Match against our command string
                    boolean match = command.toString().equals(shutdown);
                    if (match) {
                        break;
                    } else
                        log.warn("StandardServer.await: Invalid command '"
                                + command.toString() + "' received");
                }
            } finally {
                ServerSocket serverSocket = awaitSocket;
                awaitThread = null;
                awaitSocket = null;
    
                // Close the server socket and return
                if (serverSocket != null) {
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        // Ignore
                    }
                }
            }
        }
     在StandardServer调出awaite()方法循环回到Catalina的start()方法中,紧跟在awaite()方法后的是stop()方法,也即停止Server的方法,在StandardServer的stop()方法中主要完成停止Server的任务,分5步完成
  • 第一步首先判断Server是否已经启动
  • 第二部触发BEFORE_STOP_EVENT,STOP_EVENT事件,标记已经停止(started = false)
  • 第三步遍历services数组,挨个调用stop()初始化
  • 第四步触发AFTER_STOP_EVENT事件,通知监听器
  • 第五步调用stopAwait(),关闭ServerSocket,调用interrupt()退出线程。
  • /**
         * Gracefully terminate the active use of the public methods of this
         * component. This method should be the last one called on a given instance
         * of this component. It should also send a LifecycleEvent of type
         * STOP_EVENT to any registered listeners.
         * 
         * @exception LifecycleException
         *                if this component detects a fatal error that needs to be
         *                reported
         */
        publicvoidstop()throws LifecycleException {
    
            // Validate and update our current component state
            if (!started)
                return;
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
    
            lifecycle.fireLifecycleEvent(STOP_EVENT, null);
            started = false;
    
            // Stop our defined Services
            for (int i = 0; i < services.length; i++) {
                if (services[i] instanceof Lifecycle)
                    ((Lifecycle) services[i]).stop();
            }
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
    
            stopAwait();
    
        }
     

    

至此,StandardServer的初始化,启动,停止的内容完成了,StandardServer的认识也清晰了很多,StandardServer先从server.xml中加载资源完成配置,提供监听StandardServer状态方法,已经才不同生命周期操作StandardServer;在初始化中触发事件,初始化services,注册到MBeanServer,标记已经初始化,在启动中,触发启动事件,启动services,启动完成后,在由Catalina触发awaite()方法,启动ServerSocket监听请求关闭Server命令,在停止Server stop()方法中,触发停止Server事件,停止services,清除资源。注册在StandardServer上的监听器有点复杂,以后在看看是什么回事。

 

 

分享到:
评论

相关推荐

    apache-tomcat-9.0.0.M1-src

    【Apache Tomcat 9.0.0.M1 源码分析】 Apache Tomcat是一款开源的、免费的Java Servlet容器,它实现了Java EE Web应用程序的Servlet和JSP规范。源码包“apache-tomcat-9.0.0.M1-src”提供了Tomcat的核心源代码,供...

    apache-tomcat-8.5.100-src Tomcat源码解析

    源码阅读过程中,你可以关注类之间的依赖关系,了解它们如何协作处理请求,以及如何通过配置文件来调整Tomcat的行为。此外,学习Tomcat的线程模型、错误处理机制以及安全性相关的实现,都能让你更深入地理解其工作...

    apache-tomcat-8.5.50-src.zip

    Tomcat启动流程分析 组件的生命周期管理 用Lifecycle管理启动、停止、关闭 Lifecycle接口预览 几个核心方法 Server中的init方法示例 为啥StandardServer没有init方法 LifecycleBase中的init与...

    apache-tomcat-6.0.18源码

    源码分析: 1. **目录结构**:解压后的源码文件夹通常包含`bin`、`conf`、`lib`、`logs`、`webapps`、`work`等目录。`bin`存放启动和停止服务器的脚本,`conf`存储配置文件,`lib`包含运行Tomcat所需的JAR文件,`...

    tomcat7源码环境部署

    这里我们讨论的主题是"Tomcat7源码环境部署",这涉及到对Tomcat服务器的深入理解,包括其内部工作原理、源码分析以及如何在本地环境中构建和部署。下面将详细介绍相关知识点。 首先,源码部署意味着你需要从Apache ...

    apache-tomcat-7.0.57-src可导入Myeclipse

    3. **定位源代码**:在“Select root directory”中,浏览并选择你刚刚解压的Tomcat源码目录。 4. **配置构建路径**:在导入的项目中,你需要配置Java构建路径,确保所有的依赖库都正确引用。这可能包括添加JDK和...

    tomcat 7 源码分析-4 server初始化背后getServer().init()

    通过对Tomcat源码的深入理解和分析,开发者可以更好地掌握服务器的运行机制,解决性能问题,定制化配置,甚至为Tomcat贡献自己的代码。无论是新手还是经验丰富的开发者,都能从这样的源码分析中受益。

    Tomcat7 核心包 catalina包源码

    《深入解析Tomcat7 Catalina核心包源码》 Tomcat作为开源的Java Servlet容器,是Web服务器领域的重要角色,其高效、轻量级的特性深受开发者喜爱。在Tomcat7版本中,Catalina是核心组件之一,负责处理HTTP请求和响应...

    tomcat架构的源码分析

    ### Tomcat架构的源码分析 #### 一、Tomcat的架构概述 Tomcat作为一款广泛使用的开源Java Servlet容器,其内部架构设计简洁而高效。本文档将对Tomcat的架构进行详细介绍,并从源码层面深入分析其核心组成部分。...

    tomcat 6 源码

    通过研究Tomcat源码,开发者可以学习到如何构建一个高性能的Servlet容器,掌握Java Web应用的核心运行机制,这对于提升Java EE开发能力大有裨益。同时,如果你遇到Tomcat的使用问题或者想要进行定制化开发,源码分析...

    02-Tomcat源码解读1

    总的来说,Tomcat源码解读需要把握住Server和Service这两个核心组件,理解它们如何通过Connector与Engine协同工作,以及生命周期管理和启动流程的设计。同时,要关注Container的层次结构以及与配置文件的交互,这将...

    tomcat6源码

    《深入剖析Tomcat6源码》 ...通过对Tomcat6源码的分析,开发者不仅可以提升对Web服务器内部运作的理解,还能学习到如何优化性能、调试问题以及定制化开发。这将对Java Web开发和系统架构设计有着深远的影响。

    Tomcat服务器源码

    Tomcat源码主要由以下几个关键组件构成: 1. **Catalina**:这是Tomcat的核心组件,负责处理Servlet容器的主要功能,包括Servlet和JSP的加载、调度和执行。Catalina的核心类是`org.apache.catalina.core....

    我的tomcat7源码手撕过程

    ### Tomcat7源码手撕过程详解 #### Tomcat初始化流程分析 Tomcat是一个流行的Java Servlet容器,用于部署和运行Web应用程序。理解Tomcat的工作原理对于优化应用性能、解决部署问题至关重要。以下是对Tomcat7启动...

    学习tomcat源码+英文《How Tomcat Work》和每一章的相关项目+tomcat6源码依赖jar

    在深入探讨Tomcat源码之前,我们先了解一下Tomcat是什么。Tomcat是一款开源的Java Servlet容器,由Apache软件基金会开发,它实现了Java EE中的Web应用服务器部分,特别是Servlet和JavaServer Pages (JSP)规范。《How...

    tomacat-8.0.15源码

    1. 了解Servlet和JSP的工作原理:Tomcat源码提供了对Servlet生命周期的管理,以及JSP的编译和执行过程的深入理解。 2. 自定义容器:可以基于Tomcat源码创建自己的Servlet容器,满足特定需求。 3. 性能优化:通过源码...

    tomcat源码分析

    ### Tomcat源码分析 #### 一、概述 Apache Tomcat是Java开发人员最常用的Web服务器之一,它不仅能够作为独立的应用程序运行Servlet和JavaServer Pages(JSP),还可以作为一个内嵌的容器来运行Web应用。Tomcat的...

    tomcat8.0源码

    【标题】"Tomcat 8.0源码分析" 【正文】 Tomcat 8.0是Apache软件基金会的开源项目,是一个广泛使用的Java Servlet容器,实现了Java Servlet和JavaServer Pages(JSP)规范,用于部署和运行Web应用程序。源码分析...

    Tomcat源码研究

    《Tomcat源码研究》 Tomcat,全称Apache Tomcat,是一款开源的Java Servlet容器,它是Apache软件基金会Jakarta项目的重要组成部分。Tomcat作为轻量级应用服务器,广泛应用于Web应用程序的部署和运行,其核心是基于...

    tomcat6.0.39源代码

    9. **性能优化**:Tomcat源码中包含了很多可调整的参数和设置,如线程池大小、缓冲区大小、超时时间等,这些都是性能调优的关键。 10. **集群支持**:如果需要构建高可用的Tomcat集群,`Cluster`模块的源码提供了...

Global site tag (gtag.js) - Google Analytics