类加载器详解
类加载器的分类
引导类加载器属于JVM的一部分,由C++代码实现。无法直接获取到引导类加载器的对象。
引导类加载器负责加载<JAVA_HOME>\jre\lib路径下的核心类库,由于安全考虑只加载 包名 java、javax、sun开头的类。
扩展类加载器 ExtClassLoader
扩展类加载器(Extension ClassLoader):这是引导类加载器的子类,主要负责加载JDK的扩展类库(jre/lib/ext目录下的jar包)或者由系统变量java.ext.dirs指定的路径下的类库。
系统类加载器 AppClassLoader
也称应用类加载器(Application ClassLoader):这是扩展类加载器的子类,主要负责加载classpath路径下的类库,也就是我们自己编写的类。
自定义类加载器(Custom ClassLoader)
Java还允许开发者自定义类加载器,只需要继承java.lang.ClassLoader类,然后覆盖findClass()方法即可。自定义类加载器可以支持一些特殊需求,如网络类加载器,加密类加载器等。
双亲委派机制
概念
双亲委派模型是Java类加载机制的核心,这种机制能保证Java核心库的类型安全。具体来说,工作过程是这样的:
当类加载器(ClassLoader)试图加载一个类时(假设这个类还没有被加载过),它首先会将这个请求委派给其父类加载器去完成。
这样一层一层向上委派,直到最顶层的引导类加载器(Bootstrap ClassLoader)。如果父类加载器可以完成类加载任务,就成功返回;如果父类加载器无法完成加载任务,子类加载器才会尝试自己去加载。
系统类加载器会在其负责的搜索范围内(即系统类路径,由java.class.path系统属性指定)查找并加载这个类。在这个搜索范围内,本地类路径的搜索时机是先于jar包中类路径的,如果你的本地类路径和jar包类路径有重名类,那在你的jar包在你的同名类之前被找到,jar包中的类就会被加载,而你的同名类则不会被加载。
在这个过程中,如果没有任何一个类加载器能够加载这个类,那么会抛出ClassNotFoundException异常。
好处
避免了类的重复加载:当父类加载器已经加载了该类时,子类加载器就没有必要再加载一次。
保护了Java核心库的安全:即使你编写了一个名为java.lang.Object的类,它也无法被加载。因为在Java的核心库中已经存在了一个Object类,由引导类加载器去加载。双亲委派机制保证了这个类由引导类加载器加载,因此你自定义的Object类永远不会被加载。
tomcat类加载器
Tomcat 本身并没有打破 Java 的类加载机制,而是按照 Java 的类加载原理设计了自己的类加载器。Java 的类加载机制是由多个类加载器组成的,包括引导类加载器、扩展类加载器和应用类加载器等。Tomcat 使用了这些类加载器并进行了扩展,以支持其 Web 应用的部署和运行。
在 Tomcat 中,每个 Web 应用都有自己的类加载器,这意味着应用之间的类加载是隔离的。这种设计确保了多个应用可以独立运行而不互相干扰,也就是说,一个应用中的类加载和资源不会影响到其他应用,假设我们有2个Web项目,均有一个类spring.wang.schedule.myTimer,tomcat如何保证它们不冲突呢?确保每个Web项目打包成独立的WAR文件,Tomcat在加载WAR文件时会为每个Web应用创建自己的ClassLoader,从而实现类的隔离。