`
Donald_Draper
  • 浏览: 984971 次
社区版块
存档分类
最新评论

Tomcat的Server初始化及启动过程

阅读更多
Tomcat7,启动过程(BootStrap、Catalina):http://donald-draper.iteye.com/blog/2326533
Tomcat的Engine初始化,启动过程:http://donald-draper.iteye.com/blog/2327119(看完这篇文章,再看Engine初始化,启动过程)
通过分析Tomcat的启动过程,我们可以看出Tomcat的Server的启动关键在
load方法和start方法,如下:
public class Catalina {  
    protected String configFile = "conf/server.xml";  
    protected Server server = null; 
       //加载Server实例  
    public void load() {  
        getServer().setCatalina(this);  
        try {  
        //初始化Server  
            getServer().init();
        }   
    public void start() {  
        if (getServer() == null) {  
        //加载Server实例  
            load();  
        }  
        long t1 = System.nanoTime();  
        try {  
        //启动Server  
            getServer().start();  
        } 
    }  
} 

而这两个方法都是调用的Server方法,下面来看一下StandardServer的这两个方法
//<Server>
public final class StandardServer extends LifecycleMBeanBase implements Server {
   //看到一下变量,是否会想到Server.xml中的<Server>配置项
    //<GlobalNamingResources>
    private javax.naming.Context globalNamingContext = null;
    private NamingResources globalNamingResources = null;
    private static final String info =
        "org.apache.catalina.core.StandardServer/1.0";
    private NamingContextListener namingContextListener = null;
    //<Server port="8005" shutdown="SHUTDOWN">
    private int port = 8005;
    private String address = "localhost";
    private Random random = null;
    <Service name="Catalina">
    private Service services[] = new Service[0];
    private final Object servicesLock = new Object();
    private String shutdown = "SHUTDOWN";
    private static final StringManager sm =
        StringManager.getManager(Constants.Package);
    PropertyChangeSupport support = new PropertyChangeSupport(this);
    private volatile boolean stopAwait = false;
    private Catalina catalina = null;
    private ClassLoader parentClassLoader = null;
    private volatile Thread awaitThread = null;
    private volatile ServerSocket awaitSocket = null;
}

Catatlina的load方法实际上,是调用的Server.init方法,F3到init的定义,我们
可以看到这个方法是在Lifecycle类中
public interface Lifecycle {
    //生命周期状态事件
    public static final String BEFORE_INIT_EVENT = "before_init";
    public static final String AFTER_INIT_EVENT = "after_init";
    public static final String START_EVENT = "start";
    public static final String BEFORE_START_EVENT = "before_start";
    public static final String AFTER_START_EVENT = "after_start";
    public static final String STOP_EVENT = "stop";
    public static final String BEFORE_STOP_EVENT = "before_stop";
    public static final String AFTER_STOP_EVENT = "after_stop";
    public static final String AFTER_DESTROY_EVENT = "after_destroy";
    public static final String BEFORE_DESTROY_EVENT = "before_destroy";
    public static final String PERIODIC_EVENT = "periodic";
    public static final String CONFIGURE_START_EVENT = "configure_start";
    public static final String CONFIGURE_STOP_EVENT = "configure_stop";
    //留给子类扩展
    public void init() throws LifecycleException;
}

实际上Tomcat容器中Server,Service,Container(Engine,HOST),Connector的生命周期都是通过Lifecycle
来管理,StandardServer extends LifecycleMBeanBase,我们来查看一下
//LifecycleMBeanBase,JMX管理MBeanServer
public abstract class LifecycleMBeanBase extends LifecycleBase{
    private String domain = null;
    private ObjectName oname = null;
    protected MBeanServer mserver = null;
 @Override
    //注册Mbean到JMX
    protected void initInternal() throws LifecycleException {
        
        // If oname is not null then registration has already happened via
        // preRegister().
        if (oname == null) {
            mserver = Registry.getRegistry(null, null).getMBeanServer();
            oname = register(this, getObjectNameKeyProperties());
        }
    }
}

再查看LifecycleBase
public abstract class LifecycleBase implements Lifecycle {
 @Override
    public final synchronized void init() throws LifecycleException {
        if (!state.equals(LifecycleState.NEW)) {
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
        }
        setStateInternal(LifecycleState.INITIALIZING, null, false);
        try {
	    //这个就是我们要找的Server,load过程的切入点;
            initInternal();
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            setStateInternal(LifecycleState.FAILED, null, false);
            throw new LifecycleException(
                    sm.getString("lifecycleBase.initFail",toString()), t);
        }
        setStateInternal(LifecycleState.INITIALIZED, null, false);
    }
    //留给子类扩展  
    protected abstract void initInternal() throws LifecycleException;
}

//来看一下LifecycleState
public enum LifecycleState {
    NEW(false, null),
    INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
    INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
    STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
    STARTING(true, Lifecycle.START_EVENT),
    STARTED(true, Lifecycle.AFTER_START_EVENT),
    STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
    STOPPING(false, Lifecycle.STOP_EVENT),
    STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
    DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
    DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
    FAILED(false, null),
    MUST_STOP(true, null),
    MUST_DESTROY(false, null);
    private final boolean available;
    private final String lifecycleEvent;

    private LifecycleState(boolean available, String lifecycleEvent) {
        this.available = available;
        this.lifecycleEvent = lifecycleEvent;
    }
    public boolean isAvailable() {
        return available;
    }
    public String getLifecycleEvent() {
        return lifecycleEvent;
    }
}

从LifecycleBase的init方法可以看出,init方法实际上,调用的是initInternal方法,
而这个方法为抽象,待子类去扩展,而生命周期的状态是通过LifecycleState( ENUM )
枚举类描述。
现在回到Server的initInternal的方法:
//<Server>
public final class StandardServer extends LifecycleMBeanBase implements Server {
    @Override
    protected 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 names
        onameStringCache = register(new StringCache(), "type=StringCache");
        //注册MBeanFactory
        MBeanFactory factory = new MBeanFactory();
        factory.setContainer(this);
        onameMBeanFactory = register(factory, "type=MBeanFactory");
        //注册全局命名资源
        globalNamingResources.init();
        // Populate the extension validator with JARs from common and shared
        // class loaders
        if (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 loaders
            while (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);
                                }
                            } 
                        }
                    }
                }
                cl = cl.getParent();
            }
        }
        // 初始化Service
        for (int i = 0; i < services.length; i++) {
	    // 初始化Service
            services[i].init();
        }
    }
}

//下面来分析 getServer().start(),Server的start方法与init的方法类似,定义在
Lifecycle,实现在LifecycleBase,我们来看LifecycleBase
public abstract class LifecycleBase implements Lifecycle {
	@Override
    public final synchronized void start() throws LifecycleException {
        if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
                LifecycleState.STARTED.equals(state)) {
            if (log.isDebugEnabled()) {
                Exception e = new LifecycleException();
                log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
            } else if (log.isInfoEnabled()) {
                log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
            }
            return;
        }
        if (state.equals(LifecycleState.NEW)) {
            init();
        } else if (state.equals(LifecycleState.FAILED)) {
            stop();
        } else if (!state.equals(LifecycleState.INITIALIZED) &&
                !state.equals(LifecycleState.STOPPED)) {
            invalidTransition(Lifecycle.BEFORE_START_EVENT);
        }
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        try {
	    //关键切入点
            startInternal();
        }
        if (state.equals(LifecycleState.FAILED)) {
            stop();
        } else if (!state.equals(LifecycleState.STARTING)) {
            invalidTransition(Lifecycle.AFTER_START_EVENT);
        } else {
            setStateInternal(LifecycleState.STARTED, null, false);
        }
    }
    //留给父类扩展
    protected abstract void startInternal() throws LifecycleException;
 }

再回到现在回到Server的startInternal的方法:
//<Server>
public final class StandardServer extends LifecycleMBeanBase implements Server {
 @Override
    protected void startInternal() throws LifecycleException {
       //触发CONFIGURE_START_EVENT事件
        fireLifecycleEvent(CONFIGURE_START_EVENT, null);
	//设置状态为开始
        setState(LifecycleState.STARTING);
        globalNamingResources.start();
        // Start our defined Services
        synchronized (servicesLock) {
            for (int i = 0; i < services.length; i++) {
	        //启动Service
                services[i].start();
            }
        }
    }
}

我们再来看一下StandardServer的addService方法
//添加Service
@Override
    public void addService(Service service) {
        //将Service与Server关联
        service.setServer(this);
        synchronized (servicesLock) {
	    //下面几行代码很有意义,用的是数组而不是 List 集合,
	    //这个从性能角度考虑可以理解,有趣的是这里用了数组但是并没有向我们平常那样,
	    //一开始就分配一个固定大小的数组,
	    //它这里的实现机制是:重新创建一个当前大小的数组对象,
	    //然后将原来的数组对象 copy 到新的数组中,这种方式实现了类似的动态数组的功能,
	    //这种实现方式,值得我们以后拿来借鉴。
            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
                    service.start();
                } 
            }
            // Report this property change to interested listeners
            support.firePropertyChange("service", null, service);
        }
}

至此,Server的init和Start方法已经分析完,下面我们来看一下StandardService,从以上的分析,
我们只需要查看initInternal和startInternal即可
//<Service name="Catalina">
public class StandardService extends LifecycleMBeanBase implements Service {
 private static final String info =
        "org.apache.catalina.core.StandardService/1.0";
    //  <Service name="Catalina">
    private String name = null;
    private static final StringManager sm =
        StringManager.getManager(Constants.Package);
    private Server server = null;
    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
    /*<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    -->
    <!-- Define a SSL HTTP/1.1 Connector on port 8443
         This connector uses the BIO implementation that requires the JSSE
         style configuration. When using the APR/native implementation, the
         OpenSSL style configuration is required as described in the APR/native
         documentation -->
    <!--
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
    -->
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    */
    protected Connector connectors[] = new Connector[0];
    private final Object connectorsLock = new Object();
    /*<!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->*/
    //线程执行器
    protected ArrayList<Executor> executors = new ArrayList<Executor>();
    /*
    <!-- You should set jvmRoute to support load-balancing via AJP ie :
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
    -->
    <Engine name="Catalina" defaultHost="localhost">
      <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
      -->
      <!-- Use the LockOutRealm to prevent attempts to guess user passwords
           via a brute-force attack -->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />

      </Host>
    </Engine>*/
    //Engine,Host,Realm,都是Container
    protected Container container = null;
    private ClassLoader parentClassLoader = null;

    @Override
    protected void initInternal() throws LifecycleException {
        //注册Service到JMX
        super.initInternal();
	//初始化Container
        if (container != null) {
            container.init();
        }
        //初始化Executors
        for (Executor executor : findExecutors()) {
            if (executor instanceof LifecycleMBeanBase) {
                ((LifecycleMBeanBase) executor).setDomain(getDomain());
            }
            executor.init();
        }
        synchronized (connectorsLock) {
            for (Connector connector : connectors) {
                try {
		    //初始化Connector
                    connector.init();
                } 
            }
        }
    }
    @Override
    protected void startInternal() throws LifecycleException {
        if(log.isInfoEnabled())
            log.info(sm.getString("standardService.start.name", this.name));
	//设置Service状态
        setState(LifecycleState.STARTING);
        if (container != null) {
            synchronized (container) {
	        //启动container
                container.start();
            }
        }
        synchronized (executors) {
            for (Executor executor: executors) {
	        //启动executor
                executor.start();
            }
        }
        synchronized (connectorsLock) {
            for (Connector connector: connectors) {
                try {
                    if (connector.getState() != LifecycleState.FAILED) {
		        //启动connector
                        connector.start();
                    }
                } 
            }
        }
    }

     * Set the <code>Container</code> that handles requests for all
     * <code>Connectors</code> associated with this Service.
    /*<Service>
	    <Engine>
	    </Engine>
    </Service>*/
    //Container处理所有请求
    public void setContainer(Container container) {
        Container oldContainer = this.container;
        if ((oldContainer != null) && (oldContainer instanceof Engine))
            ((Engine) oldContainer).setService(null);
        this.container = container;
        if ((this.container != null) && (this.container instanceof Engine))
            ((Engine) this.container).setService(this);
        if (getState().isAvailable() && (this.container != null)) {
            try {
	        //启动Engine
                this.container.start();
            } 
        }
        if (getState().isAvailable() && (oldContainer != null)) {
            try {
                oldContainer.stop();
            } 
        }
        // Report this property change to interested listeners
        support.firePropertyChange("container", oldContainer, this.container);

    }
    //添加Connector
    public void addConnector(Connector connector) {
        synchronized (connectorsLock) {
	    //这个与Server.addService一样的理念
            connector.setService(this);
            Connector results[] = new Connector[connectors.length + 1];
            System.arraycopy(connectors, 0, results, 0, connectors.length);
            results[connectors.length] = connector;
            connectors = results;
            if (getState().isAvailable()) {
                try {
                    connector.start();
                } 
            }
            // Report this property change to interested listeners
            support.firePropertyChange("connector", null, connector);
        }
    }
    //添加Executor
    public void addExecutor(Executor ex) {
        synchronized (executors) {
            if (!executors.contains(ex)) {
                executors.add(ex);
                if (getState().isAvailable())
                    try {
                        ex.start();
                    } 
            }
        }
    }
}

//Constants
public class Constants {
    public static final String Package = "org.apache.catalina.core";
    public static final int MAJOR_VERSION = 3;
    public static final int MINOR_VERSION = 0;
    public static final String JSP_SERVLET_CLASS =
        "org.apache.jasper.servlet.JspServlet";
}

从分析StandardService可以看出StandardService主要组成部分为Container(Engine)
,Executors,Connectors,initInternal与startInternal分别初始化和启动Container(Engine),Executors,Connectors。
总结:实际上Tomcat容器中Server,Service,Container(Engine,HOST),Connector的生命周期都是通过Lifecycle来管理,Catalina依托于Server,而Server的服务对象为Service;Service的主要组成部分为Container(Engine),Executors,Connectors,Server的初始化与启动实际上,为初始化和启动Container(Engine),Executors,Connectors,下面的章节,我们分别来讲Container(Engine),Executors,Connectors
0
0
分享到:
评论

相关推荐

    tomcat启动不了问题处理

    本文将详细探讨导致Tomcat启动失败的原因及相应的解决方法,帮助读者有效解决这一问题。 #### 一、常见原因分析 1. **JRE/JDK版本不兼容** - Tomcat的运行依赖于JRE或JDK环境。如果安装的JRE/JDK版本与Tomcat不...

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

    【标题】:“Tomcat 7 源码分析 - 4 server初始化背后getServer().init()” 在这篇文章中,我们将深入探讨Apache Tomcat 7服务器的内部工作机制,重点关注`getServer().init()`方法在服务器初始化过程中的作用。...

    Tomcat启动分析以及如何启动

    这个脚本会读取`server.xml`配置文件,初始化Tomcat环境,并启动必要的组件。 总结:Tomcat的启动分析涉及其组件间的交互和配置文件的解读。理解这些原理有助于我们更好地管理和优化Tomcat服务器,确保Web应用的...

    Tomcat启动顺序

    在启动过程中,Tomcat还会进行一系列的初始化操作,例如解析配置文件,创建和配置各个组件,启动监听器和管道等。此外,对于每个Web应用程序,Tomcat还会执行Servlet的加载和初始化,包括读取`web.xml`部署描述符,...

    Tomcat 6.0启动过程分析

    从 `Bootstrap` 类开始,逐步初始化类加载器、加载配置文件,直到启动服务器并监听端口,最终形成一个完整的 Tomcat 启动过程。这一过程不仅揭示了 Tomcat 内部工作原理,也为进一步理解和优化 Tomcat 配置提供了...

    tomcat启动原理解析

    在启动过程中,它会创建并初始化各个容器,如Host、Context等。 - `Host`代表域名,`Context`代表Web应用,每个`Context`对应一个`webapps`下的目录或WAR文件。 6. **加载Web应用** - `Context`容器会扫描`...

    Tomcat 6 启动过程分析.doc

    总结来说,Tomcat 6的启动过程涉及到Bootstrap类的初始化、Catalina类的加载和配置解析,以及Digester的XML解析功能。这个过程保证了Tomcat能够正确地加载和应用配置,启动并运行Java Web应用程序。理解这一过程对于...

    TOMCAT源码分析(启动框架)

    1. **初始化配置**:Tomcat首先读取`conf/server.xml`配置文件,解析各个组件的配置信息,构建组件层次结构。 2. **加载服务**:根据配置,Tomcat创建Service对象,Service由一个或多个Connector和一个Engine组成。...

    tomcat启动服务运行servlet

    标题“Tomcat启动服务运行Servlet”涉及到的是Java Web开发中的核心概念,主要涵盖Tomcat服务器的启动过程以及Servlet的执行机制。Tomcat是一款开源、免费的Web应用服务器,广泛用于部署Java Servlet和JavaServer ...

    我的tomcat7源码手撕过程

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

    java tomcat server应用配置

    - **作用**:作为JavaWeb应用的配置文件,采用XML格式,Servlet容器从中读取配置信息,如Servlet的映射路径、初始化参数等。 - **示例配置**: ```xml &lt;servlet-name&gt;HelloServlet &lt;servlet-class&gt;...

    TOMCAT的启动.rar

    - 首先,Tomcat读取`server.xml`配置文件,初始化必要的组件和服务。 - 接着,Tomcat会加载`WEB-INF/web.xml`文件,这是每个Web应用程序的部署描述符,定义了Servlet、过滤器和监听器等。 - 然后,Tomcat创建并...

    tomcat不能启动的原因总结

    ### Tomcat不能启动的原因及解决方法 #### 一、引言 Apache Tomcat是一款开源的Servlet容器,主要用于部署Java Web应用程序。然而,在实际使用过程中,可能会遇到Tomcat无法正常启动的情况。本文将根据提供的文件...

    Linux 部署jenkins war包直接tomcat启动

    6. **等待Jenkins初始化**:当Tomcat启动并加载WAR包后,Jenkins会开始初始化过程。这个过程可能需要几分钟,取决于服务器性能和网络速度。 7. **访问Jenkins**:打开浏览器,输入`...

    tomcat9 源码学习

    2. **生命周期管理**:Tomcat中的每个组件都有其特定的生命周期,包括初始化、启动、暂停、恢复、停止和销毁。了解这些状态转换有助于理解服务的启动和关闭过程。 3. **容器概念**:在Tomcat中,容器是一个可以包含...

    Tomcat5启动流程与配置详解 .

    - 加载`$CATALINA_HOME/bin/bootstrap.jar`初始化Tomcat,并执行`Main`方法。 - 加载`$JAVA_HOME/lib/tools.jar`,Sun的工具类,包括编译JSP为Servlet的工具类。 - **Common**: - 这个目录下的类虽然对Tomcat和...

    ant启动tomcat

    此外,脚本还提供了初始化环境的功能,如设置环境变量、构建类路径等,确保了构建过程能够顺利进行。最后,通过显示帮助信息,为用户提供了一种便捷的方式了解构建脚本的使用方法及各个目标的作用。这种基于Ant的...

    Tomcat服务器配置、启动分析、Servlet文件配置

    `Tomcat启动分析-Servlet-Web.xml.doc`文档可能涵盖了启动过程中的关键步骤,包括加载`context.xml`(用于全局配置)、解析`web.xml`(Web应用的部署描述符)以及初始化Servlet和过滤器等。在启动过程中,Tomcat会...

    tomcat启动脚本

    这些脚本负责初始化Java环境,设置系统路径,加载Tomcat服务器的类和配置,并最终启动服务器。 1. **`catalina.sh/bat`脚本**:这是启动Tomcat的核心脚本。它首先检查Java环境,确保JAVA_HOME环境变量已经正确设置...

Global site tag (gtag.js) - Google Analytics