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

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
分享到:
评论

相关推荐

    阿里云Centos7下安装Redis及tomcat设置自启动的方法

    Redis安装配置 ... ...$ tar xzf redis-4.0.2.tar.gz $ cd redis-4.0.2 $ make $ make install //将可执行程序复制到/usr/local/bin中 启动redis 1.直接启动 ...$ cd redis-4.0.2 ...3.通过初始化脚本启动Redis (1)配置初

    myTomcat:WebServer + Tomcat源码分析总结

    来自《深入剖析Tomcat》 ...前导工作: org.apache.catalina.startup.Bootstrap启动startup.sh/...StandardServer的初始化(),start()方法调用所有的服务组件(数组)StandardService的初始化(),start()方法,

    mysql-java8-tomcat8

    7\初始化MySQL数据库 ca mysqld --initialize 8\查看root密码 iFngLyRoE5+x cat /var/log/mysqld.log 在这个文件里面有root的临时密码 9\更改mysql数据库目录的所属主和所属组权限 chown mysql:mysql /var/lib/...

    优化Tomcat配置(内存、并发、缓存等方面)方法详解

    -Xms java虚拟机初始化时的最小内存; -Xmx java虚拟机可使用的最大内存; -XX: PermSize 内存永久保留区域 -XX:MaxPermSize 内存最大永久保留区域 服务器参数配置 现公司服务器内存一般都可以加到最大2G ,...

    Java的过滤器与拦截器的区别.docx

    启动容器后当然是开始进行初始化。 1 private void selfInitialize(ServletContext servletContext) throws ServletException { 2 prepareWebApplicationContext(servletContext); 3 registerApplicationScope...

    JAVA商业项目源代码--商铺经营管理系统(挥泪奉献!!!)

    项目编译成功后,完成了数据库的初始化! 3. 重新启动TOMCAT 5.5 系统的运行地址: http://localhost:8080/businessMis 初始用户名: admin 登录密码: 111111 登录后可更改用户的权限以便能使用系统...

    how-tomcat-works

    19.4 初始化ManagerServlet 152 19.5 列出已经部署的web应用 153 19.6 启动web应用 154 19.7 关闭web应用 155 第20章 基于JMX的管理 156 20.1 jmx简介 156 20.2 jmx api 157 20.2.1 MBeanServer 157 20.2.2 Object...

    tomcat性能优化方式简单整理

    Tomcat本身优化 Tomcat内存优化 ... Xms java虚拟机初始化时的最小内存 Xmx java虚拟机可使用的最大内存 XX: PermSize 内存永久保留区域 XX:MaxPermSize 内存最大永久保留区域 配置示例: JAVA_OPTS=’-Xms

    看透springMvc源代码分析与实践

    7.1 Tomcat的顶层结构及启动过程44 7.1.1 Tomcat的顶层结构44 7.1.2 Bootstrap的启动过程45 7.1.3 Catalina的启动过程47 7.1.4 Server的启动过程48 7.1.5 Service的启动过程50 7.2 Tomcat的生命周期管理52 ...

    How Tomcat Works: A Guide to Developing Your Own Java Servlet Container

    19.4 初始化ManagerServlet 152 19.5 列出已经部署的web应用 153 19.6 启动web应用 154 19.7 关闭web应用 155 第20章 基于JMX的管理 156 20.1 jmx简介 156 20.2 jmx api 157 20.2.1 MBeanServer 157 20.2.2 Object...

    办公自动化管理系统

    这时在windows的系统托盘中会显示标识Tomcat服务器启动状态的图标,如果显示为,则说明Tomcat服务器没有启动,这时可以在该图标上单击鼠标右键在弹出的快捷菜单中选择“Start Service”菜单项启动Tomcat服务器,启动...

    java论坛一键搭建Easyjsprun! v6.0.1 UFT-8 For windows 110530.zip

    | ---conf/server.xml (Tomcat 配置文件) | | | ---webapps/ROOT (论坛站点根目录) | ---apache2.2(apache 程序目录) | | | ---conf/httpd.conf (Apache 配置文件) | | | ---modules/mod_jk.so ...

    java论坛一键搭建Easyjsprun! v6.0.1 GBK For windows 110530.zip

    | ---conf/server.xml (Tomcat 配置文件) | | | ---webapps/ROOT (论坛站点根目录) | ---apache2.2(apache 程序目录) | | | ---conf/httpd.conf (Apache 配置文件) | | | ---modules/mod_jk.so ...

    Java物资管理系统源码+程序使用说明文档.zip

    (2)打开“系统管理/系统初始化”菜单项:将当前所有数据进行系统初始化操作。 注意:在初始化前最好先对数据进行备份,以免造成数据丢失。 (3)单击“修改密码”按钮,修改当前正在使用用户密码。 (4)打开...

    智能开发平台 DOROODO

    框架介绍】 doroodo是一个有表单设计、代码生成、图表封装、多项目同时开发、通用业务模块的基于fixflow工作流的S2SH开发平台。...将doroodo发布tomcat中,启动tomcat 初始化的用户名:admin 密码:123456

    Jpom项目监控软件-其他

    【Server】初始化安装不能自动登录 【Server】页面组件采用国际化采用 zh_cn 【Server】服务器中验证码无法加载 【Agent】解决控制台输出 Failed to check connection: java.net.ConnectException: Connection ...

    JSP动态网页制作基础培训教程源代码.rar

    读者应该确保计算机上安装有SQL Server 2000服务器,启动SQL Server服务后,打开查询分析器,然后执行本章目录下的db.sql文件自动生成并初始化数据库。 2.将本章的代码(文件夹news)拷贝到Tomcat服务器安装目录的...

    JAVA上百实例源码以及开源项目源代码

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    JAVA上百实例源码以及开源项目

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

Global site tag (gtag.js) - Google Analytics