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; }
// 模拟Tomcat的CommonClassLoader 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类加载的委托机制。
这种层次结构允许类加载器首先在本地查找类,找不到时再委托给父加载器,既保证了类加载的高效性,又确保了类的正确加载顺序,避免了类覆盖问题。
标签:Web,name,parent,ClassLoader,Tomcat,加载,自定义 From: https://www.cnblogs.com/2324hh/p/18188818