Tomcat源码分析(一)--初始化init(Bootstrap启动)

本文详细解析了Tomcat服务器的启动流程,从初始化ClassLoader到创建核心组件,再到启动服务器的具体步骤,帮助读者深入理解Tomcat的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下载tomcat 8.0源码可以到tomcat官网去下载   source code distributions 选择zip,下载完新建一个pom.xml就可以导入到eclipse中了。其实知道Tomcat源码就可以把spring Web项目整个运行流程就可以想明白。

 

一、Tomcat总体结构

 

一个Tomcat中只有一个Server,一个Server可以包含多个Service,一个Service只有一个Cotainer,但可以有多个Connectors,

(因为一个服务可以有多个连接,如同时提供http和https连接,也可以提供相同协议不同端口的接口)

Tomcat最顶层的容器就叫Server,代表整个服务器,Server包含一个或多个的Service.

Service包括了Connector和Container.

 

Tomcat里的Server由org.apache,catalina.startup.Catalina来管理。Catalina类的三个方法start,stop,load分别管理整个服务器的生命周期。

load方法用于根据conf/server.xml文件创建Server并调用Server的init方法进行初始化,

       ---》 Catalina类的load()方法详细解释在 (Tomcat源码分析(二)

start方法用于启动服务器,stop方法用于停止服务器,start和stop都调用了Server的start和stop方法。load方法内部调用了Server的init方法。

Server的start方法--->所有的Service中的start方法-->调用所有包含Connector和Container的start方法-》启动了服务器

init和stop方法也是一样。

 

  /**
     * Await and shutdown.
     */
    public void await() {

        getServer().await();

    }

Catalina的await方法--》Server的await方法 作用是进入一个循环,让主线程不会退出。

 

二、Tomcat的启动入口

       Catalina类主要负责 具体的管理类,而Bootstrap类是启动的入口(main方法)。

       Bootstrap类main方法:

  /**
     * Main method and entry point when starting Tomcat via the provided
     * scripts.
     *
     * @param args Command line arguments to be processed
     */
    public static void main(String args[]) {

        if (daemon == null) {
            // Don't set daemon until init() has completed
            Bootstrap bootstrap = new Bootstrap();
            try {
                bootstrap.init();
            } catch (Throwable t) {
                handleThrowable(t);
                t.printStackTrace();
                return;
            }
            daemon = bootstrap;
        } else {
            // When running as a service the call to stop will be on a new
            // thread so make sure the correct class loader is used to prevent
            // a range of class not found exceptions.
            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
        }

        try {
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }

            if (command.equals("startd")) {
                args[args.length - 1] = "start";
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stopd")) {
                args[args.length - 1] = "stop";
                daemon.stop();
            } else if (command.equals("start")) {
                daemon.setAwait(true);
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            } else if (command.equals("configtest")) {
                daemon.load(args);
                if (null==daemon.getServer()) {
                    System.exit(1);
                }
                System.exit(0);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            // Unwrap the Exception for clearer error reporting
            if (t instanceof InvocationTargetException &&
                    t.getCause() != null) {
                t = t.getCause();
            }
            handleThrowable(t);
            t.printStackTrace();
            System.exit(1);
        }

    }

如果args参数为空,默认执行start。

 main方法内:

bootstrap.init();

 具体的实现init()方法:

  /**
     * Initialize daemon.
     */
    public void init() throws Exception {

        initClassLoaders();

        Thread.currentThread().setContextClassLoader(catalinaLoader);

        SecurityClassLoad.securityClassLoad(catalinaLoader);

        // Load our startup class and call its process() method
        if (log.isDebugEnabled())
            log.debug("Loading startup class");
        Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.getConstructor().newInstance();

        // Set the shared extensions class loader
        if (log.isDebugEnabled())
            log.debug("Setting startup class properties");
        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);

        catalinaDaemon = startupInstance;

    }

1、初始化ClassLoader(initClassLoaders)

      创建commonLoader、catalinaLoader和sharedLoader;

 代码如下:

   private void initClassLoaders() {
        try {
            commonLoader = createClassLoader("common", null);
            if( commonLoader == null ) {
                // no config file, default to this loader - we might be in a 'single' env.
                commonLoader=this.getClass().getClassLoader();
            }
            catalinaLoader = createClassLoader("server", commonLoader); //这里如果获取不到server.loader对应的value值就会返回commonLoader。
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            handleThrowable(t);
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }

 

createClassLoader方法

代码如下:

private ClassLoader createClassLoader(String name, ClassLoader parent)
        throws Exception {

        String value = CatalinaProperties.getProperty(name + ".loader");
        if ((value == null) || (value.equals("")))
            return parent;

        value = replace(value);

        List<Repository> repositories = new ArrayList<>();

        String[] repositoryPaths = getPaths(value);

        for (String repository : repositoryPaths) {
            // Check for a JAR URL repository
            try {
                @SuppressWarnings("unused")
                URL url = new URL(repository);
                repositories.add(
                        new Repository(repository, RepositoryType.URL));
                continue;
            } catch (MalformedURLException e) {
                // Ignore
            }

            // Local repository
            if (repository.endsWith("*.jar")) {
                repository = repository.substring
                    (0, repository.length() - "*.jar".length());
                repositories.add(
                        new R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值