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

相关推荐
@ chen1 小时前
Spring Boot 解决跨域问题
java·spring boot·后端
转转技术团队2 小时前
转转上门隐私号系统的演进
java·后端
【本人】3 小时前
Django基础(二)———URL与映射
后端·python·django
Humbunklung3 小时前
Rust 模块系统:控制作用域与私有性
开发语言·后端·rust
WanderInk3 小时前
依赖对齐不再“失联”:破解 feign/BaseBuilder 错误实战
java·后端·架构
LaoZhangAI5 小时前
GPT-4o mini API限制完全指南:令牌配额、访问限制及优化策略【2025最新】
前端·后端
LaoZhangAI5 小时前
FLUX.1 API图像尺寸设置全指南:优化生成效果与成本
前端·后端
Kookoos5 小时前
ABP VNext + EF Core 二级缓存:提升查询性能
后端·.net·二级缓存·ef core·abp vnext
月初,5 小时前
SpringBoot集成Minio存储文件,开发图片上传等接口
java·spring boot·后端
KubeSphere6 小时前
全面升级!WizTelemetry 可观测平台 2.0 深度解析:打造云原生时代的智能可观测平台
后端