Tomcat中为什么要使用自定义类加载器

原创
05/13 11:01
阅读数 49

Tomcat 使用自定义类加载器主要是基于以下几个关键原因:

1.应用隔离:Tomcat作为一个Web容器,能够同时部署和运行多个Web应用程序。每个应用可能依赖不同的库版本或者包含同名类,为了确保每个应用的类库相互独立,避免类冲突,Tomcat 为每个Web应用提供了一个独立的类加载器实例,即`WebAppClassLoader`。这样,即使不同应用中存在相同的类名,它们也是被各自的应用类加载器加载,互不影响。

2.热部署与热替换:自定义类加载器支持热部署和类的热替换功能。当Web应用发生变化时,不需要重启整个Tomcat服务器,只需重新加载对应的Web应用即可。通过创建新的类加载器来加载更新后的类,旧的类加载器和旧的类可以被垃圾回收,实现类的平滑升级。

3.遵循Servlet规范:Servlet规范要求Web容器必须为每个Web应用提供独立的类加载器上下文,以满足应用的独立性和安全性需求。Tomcat的自定义类加载器体系结构正是对这一规范的实现。

4. 层次化加载机制:Tomcat的类加载器体系采用分层设计,包括但不限于以下几个关键的类加载器:


   - Bootstrap ClassLoader:负责加载JDK核心类库。
   - Common/Shared ClassLoader:加载Tomcat和所有Web应用共享的类库。
   - Catalina ClassLoader:加载Tomcat自身的类。
   - WebApp ClassLoader:为每个Web应用创建,负责加载该应用特有的类和库。
   

// 自定义类加载器的基类,模仿Tomcat中类加载器的委托逻辑
abstract class CustomClassLoader extends ClassLoader {
    protected ClassLoader parent; // 父加载器引用

    protected CustomClassLoader(ClassLoader parent) {
        super(parent);
        this.parent = parent;
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                try {
                    // Delegate to the parent class loader if not found
                    c = super.loadClass(name, false); // 正确的调用方式
                } catch (ClassNotFoundException e) {
                    // If still not found, then invoke findClass in this class loader
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

    // 抽象方法,子类需实现以定义如何查找类
    protected abstract Class<?> findClass(String name) throws ClassNotFoundException;
}
// 模拟TomcatCommonClassLoader
class CommonClassLoader extends CustomClassLoader {
    public CommonClassLoader(ClassLoader parent) {
        super(parent);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        System.out.println("CommonClassLoader wei");
        // 实现查找共享类的逻辑
        throw new ClassNotFoundException("Not implemented wei");
    }
}
// 自定义类加载器的基类,模仿Tomcat中类加载器的委托逻辑
abstract class CustomClassLoader extends ClassLoader {
    protected ClassLoader parent; // 父加载器引用

    protected CustomClassLoader(ClassLoader parent) {
        super(parent);
        this.parent = parent;
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                try {
                    // Delegate to the parent class loader if not found
                    c = super.loadClass(name, false); // 正确的调用方式
                } catch (ClassNotFoundException e) {
                    // If still not found, then invoke findClass in this class loader
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

    // 抽象方法,子类需实现以定义如何查找类
    protected abstract Class<?> findClass(String name) throws ClassNotFoundException;
}

上面三段代码分别是:一个基础的,模拟Tomcat中通用的加载逻辑;一个,代表Tomcat中用于加载共享类库的类加载器;以及一个,模拟每个Web应用独有的类加载器。在方法中,我们展示了如何通过Web应用类加载器加载类,同时这个加载器会委托给共享类加载器,模拟了Tomcat类加载的委托机制。

这种层次结构允许类加载器首先在本地查找类,找不到时再委托给父加载器,既保证了类加载的高效性,又确保了类的正确加载顺序,避免了类覆盖问题。

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部