类加载
在Java程序中,当我们需要使用到某个类时,如果此时类还没有被加载到内存,那么Java虚拟机会加载这个类的.class文件即字节码文件,经过加载、链接、初始化三个步骤,最终形成可以被使用的Java类,这就是虚拟机的类加载。
JVM中的三个类加载器
类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。通常来讲,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在通过 Java 编译器编译以后就被转换成 Java 字节代码(.class 文件)。类加载器负责加载所有的类,读取 Java 字节代码,其为所有被载入内存中的类生成一个java.lang.Class实例对象。一旦一个类被加载到JVM中,同一个类就不会被再次载入了。每一个这样的实例用来表示一个 Java 类。经过此实例的 newInstance()方法就能够建立出该类的一个对象。
-
引导类加载器
BootStrap ClassLoader,负责加载Java基础类,对应加载%JRE_HOME/lib/目录下的文件 -
拓展类加载器
Extension ClassLoader,负责加载%JRE_HOME/lib/ext目录下的jar和class等文件。 -
应用类加载器
Application ClassLoader,负责加载应用程序classpath目录下的所有jar和class等文件。 -
用户自定义类加载器
User ClassLoader
四种类加载器的层次关系:
双亲委派
JVM在加载一个类的时候,首先会先调用Application ClassLoader的loadClass()方法来加载这个类,在这个loadClass方法中会先使用Extension ClassLoader的loadClass()方法来加载这个类,同样在这个loadClass()方法中会先使用BootStrap ClassLoader的loadClass()方法来加载,如果BootStrap ClassLoader的loadClass()方法能够加载到则加载这个类成功,如果加载不到则Extension ClassLoader的loadClass()来加载,如果也加载不到,则由Application ClassLoader自己加载。因此,双亲委派的是指JVM在加载类时会先委派给BootStrap ClassLoader和Extension ClassLoader来加载,如果他们都不能加载,则由Applicaiton ClassLoader自己加载。
这样做的好处是什么?
-
防止加载同一个类。 通过判断上级加载器是否已经加载过该类,如果加载过了,则不需要重新加载,保证了数据安全。
-
采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object 对象。
双亲委派例子 以下我们新建一个包为
java.lang,类名为String的自定义类,然后定义一个public String(String string)构造方法,在main方法中通过该构造方法创建一个字符串对象,然后将其输出,我们一起看看字符串输出的是不是通过我们定义的构造方法所创建的?
package java.lang;
/**
* @Author GJY
* @Date 2021/8/5 15:20
* @Version 1.0
*/
public class String {
public String (String string){
System.out.println("点赞+关注:"+string);
}
}
//在另一个包下通过自定义的String类的构造方法创建一个String对象
public static void main(String[] args) {
String str = new String("不喝奶茶的Programmer");
System.out.println(str);
}
运行main方法后,我们会发现程序并不是输出"点赞+关注:不喝奶茶的Programmer",而只是输出了不喝奶茶的Programmer,说明我们自定义的String类并没有被加载,被加载的仍然是JDK原生的java.lang.String类,所以双亲委派机制就可以保证Java核心类库提供的类不会被自定义的类所替代。
Tomcat为什么需要自定义类加载器(为什么破坏双亲委派)
一个Tomcat中可以部署多个应用,而每个应用都存在很多类,并且每个应用中类都是独立的,全类名可以相同,比如一个订单系统中可能存在com.shop.User类,一个库存系统中可能也存在com.shop.User类,一个Tomcat不管内部部署了多少应用,Tomcat启动之后就是一个Java进程,所以如果Tomcat只存在一个类加载器,比如默认的Application ClassLoader,那么就只能加载com.shop.User类,这样子是不行的,所以在Tomcat中会为部署的每一个应用都生成一个类加载器,名字为WebAppClassLoader,优先加载应用本身的目录下的class文件,这样Tomcat中每个应用就可以使用自己的类加载器去加载自己的类,从而达到多个应用之间类的隔离,确保不出现冲突。
以上就是关类加载器、双亲委派模型的简单介绍,如果有错误的地方,还请留言指正,如果觉得本文对你有帮助那就点个赞吧😋😋
往期推荐