Tomcat源码解析(四):tomcat核心组件初始化和启动

来源:互联网 发布:大型企业网络设计方案 编辑:程序博客网 时间:2024/06/06 02:33

Tomcat在接收到用户请求时,将会通过以上组件的协作来给最终用户产生响应。首先是最外层的Server和Service来提供整个运行环境的基础设施,而Connector通过指定的协议和接口来监听用户的请求,在对请求进行必要的处理和解析后将请求的内容传递给对应的容器,经过容器一层层的处理后,生成最终的响应信息,返回给客户端。


Tomcat在提供监听服务前,具体做了什么工作?比如Server和Service以及容器是何时创建?webapps下的项目war包何时加载?同时web.xml文件解析规则?


Tomcat的初始化和启动流程主要围绕核心接口展开,比如Server、Service、Connector、Container、Engine、Host、Context、Wrapper、LifeCycle等等。


startup.bat和catalina.bat脚本

Tomcat启动可以通过startup.bat和catalina.bat脚本执行启动,前者无需参数,默认使用start参数启动Tomcat,后者则需要手动配置参数。

就像所有的Java程序都会有main()方法作为入口,Tomcat也是如此,上面两脚本最终会执行调用Bootstracp类的main()方法作为入口,而Tomcat的核心启动类是Catalina,其会解析server.xml文件并保存Server的引用。而Bootstracp作为适配器,提供多种方式适配Cataline,使Cataline启动提供多种方式。


下面看下Bootstracp的main()方法,主要工作:

1、初始化相关类加载器

2、通过反射方式创建Cataline实例

3、反射调用Cataline实例方法,设置父类加载器

4、调用Cataline实例的process方法

public static void main(String args[]) {    // Construct the class loaders we will need    ClassLoader commonLoader = null;    ClassLoader catalinaLoader = null;    ClassLoader sharedLoader = null;    // Load our startup class and call its process() method    // 反射方式创建Catalina实例    Class startupClass =        catalinaLoader.loadClass        ("org.apache.catalina.startup.Catalina");    Object startupInstance = startupClass.newInstance();    // 反射方式设置其父类加载器    String methodName = "setParentClassLoader";    Class paramTypes[] = new Class[1];    paramTypes[0] = Class.forName("java.lang.ClassLoader");    Object paramValues[] = new Object[1];    paramValues[0] = sharedLoader;    Method method =        startupInstance.getClass().getMethod(methodName, paramTypes);    method.invoke(startupInstance, paramValues);    // 调用Catalina实例的process方法    methodName = "process";    paramTypes = new Class[1];    paramTypes[0] = args.getClass();    paramValues = new Object[1];    paramValues[0] = args;    method =        startupInstance.getClass().getMethod(methodName, paramTypes);    method.invoke(startupInstance, paramValues);}
下面进去Catalina实例,首先看下Catalina类的主要成员属性:

// 当前Server配置文件位置    protected String configFile = "conf/server.xml";    // server引用    protected Server server = null;    // 是否启动    protected boolean starting = false;    // 是否关闭    protected boolean stopping = false;
接下来进入Catalina实例的process()方法
    public void process(String args[]) {    // 设置目录        setCatalinaHome();        setCatalinaBase();        try {            if (arguments(args))                // 执行                execute();        } catch (Exception e) {            e.printStackTrace(System.out);        }    }

其把工作传递给execute()方法,而execute()根据是启动命令则传递给start()方法


start()方法主要工作:

1、创建Digester实例,用于解析config/server.xml配置文件信息

2、读取config/server.xml配置文件,并根据Digester规则进行相应解析(创建所有组件,包含各个web应用)

3、执行Server的初始化initialize()方法,初始化Server所管理所有Service服务

4、执行Server的启动start()方法,启动Server所管理的所有Service服务(层层启动所有连接器和容器)

protected void start() {    // 创建Digester实例    Digester digester = createStartDigester();    // 获取conf/server.xml配置文件信息    File file = configFile();    // 当前Catalina入栈,用于设置server引用    digester.push(this);    // 解析conf/server.xml文件信息    digester.parse(is);    Thread shutdownHook = new CatalinaShutdownHook();    // 初始化和启动server    if (server instanceof Lifecycle) {        server.initialize();        ((Lifecycle) server).start();        // 主线程阻塞等待关闭命令        server.await();    }    // 关闭server    if (server instanceof Lifecycle) {        ((Lifecycle) server).stop();    }}
其中调用Server的initialize()方法在前面已经详细分析过,主要就是循环初始化每个Service服务

    public void initialize()    throws LifecycleException {        // 防止初始化两次        if (initialized)            throw new LifecycleException (                sm.getString("standardServer.initialize.initialized"));        initialized = true;        // 初始化所有Service组件        for (int i = 0; i < services.length; i++) {            services[i].initialize();        }    }
而Server的start()方法也是同样道理,依次启动每个Service服务

    public void start() throws LifecycleException {        // Validate and update our current component state        if (started)            throw new LifecycleException                (sm.getString("standardServer.start.started"));        // 触发BEFORE_START_EVENT事件,通知相关监听器        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);        // 触发START_EVENT事件        lifecycle.fireLifecycleEvent(START_EVENT, null);        started = true;        // 启动所有Service服务组件        synchronized (services) {            for (int i = 0; i < services.length; i++) {                // 判断Service是否实现Lifecycle接口                // start方法属于Lifecycle接口                if (services[i] instanceof Lifecycle)                    ((Lifecycle) services[i]).start();            }        }        // 触发AFTER_START_EVENT事件        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);    }

依次启动每个Service服务,而Service服务会依次启动所管理的每个连接器和容器。


总结Tomcat的初始化和启动过程步骤如下:

1、初始化相关类加载器commonLoader、catalinaLoader、sharedLoader;

2、反射机制创建Catalina实例,调用其setParentClassLoader(sharedLoader);

3、反射机制调用Catalina的process()方法;

4、设置基本目录,catalinaHome、catalinaBase;

5、创建Digester实例,用于解析config/server.xml配置文件信息;

6、读取config/server.xml配置文件,并根据Digester规则进行相应解析(创建所有组件,包含各个web应用);

7、执行Server的初始化initialize()方法,初始化Server所管理所有Service服务;

8、执行Server的启动start()方法,启动Server所管理的所有Service服务(层层启动所有连接器和容器);


总结Tomcat初始化和启动流程的时序图如下:







0 0
原创粉丝点击