Tomcat - 启动过程:类加载机制详解

Tomcat初始化了哪些classloader

在Bootstrap中我们可以看到有如下三个classloader

ini 复制代码
ClassLoader commonLoader = null;
ClassLoader catalinaLoader = null;
ClassLoader sharedLoader = null;

如何初始化的呢?

scss 复制代码
    private void initClassLoaders() {
        try {
//             commonLoader初始化
            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初始化, 父classloader是commonLoader
            catalinaLoader = createClassLoader("server", commonLoader);
//            sharedLoader初始化
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            handleThrowable(t);
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }

可以看出,catalinaLoader 和 sharedLoader 的 parentClassLoader 是 commonLoader。

如何创建classLoader的?

不妨再看下如何创建的?

ini 复制代码
private ClassLoader createClassLoader(String name, ClassLoader parent) throws Exception {

    String value = CatalinaProperties.getProperty(name + ".loader");
    if ((value == null) || (value.isEmpty())) {
        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 {
            URI uri = new URI(repository);
            @SuppressWarnings("unused")
            URL url = uri.toURL();
            repositories.add(new Repository(repository, RepositoryType.URL));
            continue;
        } catch (IllegalArgumentException | MalformedURLException | URISyntaxException e) {
            // Ignore
        }

        // Local repository
        if (repository.endsWith("*.jar")) {
            repository = repository.substring(0, repository.length() - "*.jar".length());
            repositories.add(new Repository(repository, RepositoryType.GLOB));
        } else if (repository.endsWith(".jar")) {
            repositories.add(new Repository(repository, RepositoryType.JAR));
        } else {
            repositories.add(new Repository(repository, RepositoryType.DIR));
        }
    }

    return ClassLoaderFactory.createClassLoader(repositories, parent);
}

方法的逻辑也比较简单就是从 catalina.property文件里找 common.loader, shared.loader, server.loader 对应的值,然后构造成Repository 列表,再将Repository 列表传入ClassLoaderFactory.createClassLoader 方法,ClassLoaderFactory.createClassLoader 返回的是 URLClassLoader,而Repository 列表就是这个URLClassLoader 可以加在的类的路径。 在catalina.property文件里

bash 复制代码
common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar" 
server.loader= 
shared.loader=

其中 shared.loader, server.loader 是没有值的,createClassLoader 方法里如果没有值的话,就返回传入的 parent ClassLoader,也就是说,commonLoader,catalinaLoader,sharedLoader 其实是一个对象。在Tomcat之前的版本里,这三个是不同的URLClassLoader对象。

ini 复制代码
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.getConstructor().newInstance();

初始化完三个ClassLoader对象后,init() 方法就使用 catalinaClassLoader 加载了org.apache.catalina.startup.Catalina 类,并创建了一个对象,然后通过反射调用这个对象的 setParentClassLoader 方法,传入的参数是 sharedClassLoader。最后吧这个 Catania 对象复制给 catalinaDaemon 属性。

相关推荐
Assby4 分钟前
如何尽可能精确计算线程池执行 shutdown() 后的耗时?
java·后端
星浩AI26 分钟前
Google 官方发布:让你的 AI 编程助手"边写、边看、边调",像人类开发者一样工作
人工智能·后端·开源
喵了个Code1 小时前
Spring Boot 3 + Spring Security + OAuth2 + Gateway企业级认证授权平台实现
后端
开心猴爷1 小时前
除了 Perfdog,如何在 Windows 环境中完成 iOS App 的性能测试工作
后端
桦说编程2 小时前
简单方法实现子任务耗时统计
java·后端·监控
盖世英雄酱581362 小时前
物品超领取损失1万事故复盘(一)
java·后端
凌览2 小时前
别再死磕 Nginx!http-proxy-middleware 低配置起飞
前端·后端
拾玖不会code2 小时前
简单分表场景下的业务发散思考:分表如何保证丝滑?
后端
CryptoRzz2 小时前
印度尼西亚(IDX)股票数据对接开发
java·后端·websocket·web3·区块链
咕白m6253 小时前
通过 C# 快速生成二维码 (QR code)
后端·.net