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 属性。

相关推荐
考虑考虑7 小时前
nginx路由重写
运维·后端·自动化运维
JaguarJack8 小时前
PHP 紧急修复两项严重 RCE 漏洞,8.2 至 8.5 用户应立即升级
后端·php·服务端
BingoGo9 小时前
PHP 紧急修复两项严重 RCE 漏洞,8.2 至 8.5 用户应立即升级
后端·php
金銀銅鐵9 小时前
[Java] 展示添加元素时 ArrayList 的内部变化
java·后端·ai编程
斌糖雪梨9 小时前
spring auth 核心流程详解
java·后端·spring
高频因子挖掘机11 小时前
本地已有一年历史数据,第二天更新别只拉“昨天一天”:量化 K 线增量同步实践
后端·github·api
高频因子挖掘机11 小时前
只补缺失日期,不重拉全部历史:增量更新 K 线应该怎么设计?
后端·github·api
Gopher_HBo11 小时前
Go reflect 包动态调用与方法反射 —Call、MakeFunc 与性能
后端
码事漫谈12 小时前
人设带处境,AI 更入戏
后端
掘金酱12 小时前
【10.24 特别活动】AI 时代,程序员的新饭碗在哪里?
前端·人工智能·后端