目录
类加载执行过程
我们看如下代码,当我们启动的时候,main方法将会被运行,这个执行过程其实是由我们的类加载器来完成的。
package com.jvm;
public class JvmRunner {
public static final int month = 5;
public void show(){
int one = 10;
int two = 11;
int result = one+two ;
System.out.println("result = " + result);
}
public static void main(String[] args) {
JvmRunner jvmRunner = new JvmRunner();
jvmRunner.show();
}
}
我们来看看等同于如下执行语句,具体来干了什么
// 切换到对应/target/classes目录中,运行.class文件
java com.jvm.JvmRunner
其中loadClass的类加载过程有如下几个步骤:
加载->验证->准备->解析->初始化->使用->卸载
- 加载:硬盘上寻找并读取对应类的class文件
- 验证:校验字节码文件得正确性
- 准备:给类的静态变量分配内存,并赋予默认值。例如:
public static final int month = 5; 这里会将基础类型的int类型赋值为0。
- 解析:将符号引用替换为直接引用。符号引用顾名思义,比如一个main方法名可以理解成一个符号,在这里将会被具体映射到内存中某个具体地址,这个就是所谓的静态链接;与之对应的就是动态链接,运行过程中将符号替换为直接引用。例如:main方法中,我们调用的show()方法;
- 初始化:对类的静态变量初始化指定的值,同时会执行静态代码快方法(注:静态代码块执行顺序优先于构造方法)
通过将class文件反编译,我们来认识一下符号引用,其中 【"Constant pool"】从#1~#60都是符号引用代表的名称。
控制台执行脚本:javap -c -v com.jvm.JvmRunner
Classfile /target/classes/com/jvm/JvmRunner.class
Last modified 2022-5-17; size 1020 bytes
MD5 checksum f723d16e6807d1f8c4eb64adc08753e1
Compiled from "JvmRunner.java"
public class com.jvm.JvmRunner
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #13.#37 // java/lang/Object."<init>":()V
#2 = Fieldref #38.#39 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Class #40 // java/lang/StringBuilder
#4 = Methodref #3.#37 // java/lang/StringBuilder."<init>":()V
#5 = String #41 // result =
#6 = Methodref #3.#42 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#7 = Methodref #3.#43 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#8 = Methodref #3.#44 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#9 = Methodref #45.#46 // java/io/PrintStream.println:(Ljava/lang/String;)V
#10 = Class #47 // com/jvm/JvmRunner
#11 = Methodref #10.#37 // com/jvm/JvmRunner."<init>":()V
#12 = Methodref #10.#48 // com/jvm/JvmRunner.show:()V
#13 = Class #49 // java/lang/Object
#14 = Utf8 month
#15 = Utf8 I
#16 = Utf8 ConstantValue
#17 = Integer 5
#18 = Utf8 <init>
#19 = Utf8 ()V
#20 = Utf8 Code
#21 = Utf8 LineNumberTable
#22 = Utf8 LocalVariableTable
#23 = Utf8 this
#24 = Utf8 Lcom/jvm/JvmRunner;
#25 = Utf8 show
#26 = Utf8 one
#27 = Utf8 two
#28 = Utf8 result
#29 = Utf8 main
#30 = Utf8 ([Ljava/lang/String;)V
#31 = Utf8 args
#32 = Utf8 [Ljava/lang/String;
#33 = Utf8 jvmRunner
#34 = Utf8 MethodParameters
#35 = Utf8 SourceFile
#36 = Utf8 JvmRunner.java
#37 = NameAndType #18:#19 // "<init>":()V
#38 = Class #50 // java/lang/System
#39 = NameAndType #51:#52 // out:Ljava/io/PrintStream;
#40 = Utf8 java/lang/StringBuilder
#41 = Utf8 result =
#42 = NameAndType #53:#54 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#43 = NameAndType #53:#55 // append:(I)Ljava/lang/StringBuilder;
#44 = NameAndType #56:#57 // toString:()Ljava/lang/String;
#45 = Class #58 // java/io/PrintStream
#46 = NameAndType #59:#60 // println:(Ljava/lang/String;)V
#47 = Utf8 com/jvm/JvmRunner
#48 = NameAndType #25:#19 // show:()V
#49 = Utf8 java/lang/Object
#50 = Utf8 java/lang/System
#51 = Utf8 out
#52 = Utf8 Ljava/io/PrintStream;
#53 = Utf8 append
#54 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#55 = Utf8 (I)Ljava/lang/StringBuilder;
#56 = Utf8 toString
#57 = Utf8 ()Ljava/lang/String;
#58 = Utf8 java/io/PrintStream
#59 = Utf8 println
#60 = Utf8 (Ljava/lang/String;)V
{
public static final int month;
descriptor: I
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: int 5
public com.jvm.JvmRunner();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/jvm/JvmRunner;
public void show();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=3, locals=4, args_size=1
0: bipush 10
2: istore_1
3: bipush 11
5: istore_2
6: iload_1
7: iload_2
8: iadd
9: istore_3
10: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
13: new #3 // class java/lang/StringBuilder
16: dup
17: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
20: ldc #5 // String result =
22: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: iload_3
26: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
29: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
32: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
35: return
LineNumberTable:
line 7: 0
line 8: 3
line 9: 6
line 10: 10
line 11: 35
LocalVariableTable:
Start Length Slot Name Signature
0 36 0 this Lcom/jvm/JvmRunner;
3 33 1 one I
6 30 2 two I
10 26 3 result I
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: new #10 // class com/jvm/JvmRunner
3: dup
4: invokespecial #11 // Method "<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #12 // Method show:()V
12: return
LineNumberTable:
line 13: 0
line 14: 8
line 15: 12
LocalVariableTable:
Start Length Slot Name Signature
0 13 0 args [Ljava/lang/String;
8 5 1 jvmRunner Lcom/jvm/JvmRunner;
MethodParameters:
Name Flags
args
}
SourceFile: "JvmRunner.java"
类加载器和双亲委派机制
- 引导类加载器:负责加载支撑jvm运行的位于jre的lib目录下得核心类库,比如rt.jar、charsets.jar等。
- 扩展类加载器:ext目录下得jar包。
- 应用程序类加载器:负责加载classpath路径下的类包,也就是我们写得代码类。
- 自定义加载器:负责加载用户自定义路径下得类包。
我们先通过一个代码示例来了解一下各个类加载器
package com.jvm;
import com.sun.crypto.provider.DESKeyFactory;
import sun.misc.Launcher;
import java.net.URL;
/**
* 我们所看到的应用程序类加载器包含引导类加载器的jar包,是因为懒加载问题哟
* jar包中的方法,是用到的时候才会加载
*/
public class ClassLoaderUnit {
public static void main(String[] args) {
System.out.println("String类属于rt.jar为引导类加载器,c++实现无法查看,返回结果=null;result="+String.class.getClassLoader());
System.out.println("扩展类加载器,返回结果:sun.misc.Launcher$ExtClassLoader@17d10166;result="+DESKeyFactory.class.getClassLoader());
System.out.println("用户自己类加载器,返回结果:sun.misc.Launcher$AppClassLoader@18b4aac2;result="+ClassLoaderUnit.class.getClassLoader());
System.out.println("-----------\n");
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
ClassLoader extClassLoader = appClassLoader.getParent();
ClassLoader bootstrapLoader = extClassLoader.getParent();
System.out.println("bootstrapLoader为c++实现,所以返回结果为null;result="+bootstrapLoader);
System.out.println("appClassLoader的父类加载器为extClassLoader;result="+extClassLoader);
System.out.println("SystemClassLoader默认就是appClassLoader,就是我们说的默认类加载器;result="+appClassLoader);
System.out.println("-----------\n");
System.out.println("打印bootstrapLoader加载的文件");
URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urLs.length; i++) {
System.out.println(urLs[i]);
}
System.out.println("-----------\n");
System.out.println("打印extstrapLoader加载的文件");
System.out.println(System.getProperty("java.ext.dirs"));
System.out.println("-----------\n");
System.out.println("打印appstrapLoader加载的文件");
System.out.println(System.getProperty("java.class.path"));
}
/*
结果一览:
String类属于rt.jar为引导类加载器,c++实现无法查看,返回结果=null;result=null
扩展类加载器,返回结果:sun.misc.Launcher$ExtClassLoader@17d10166;result=sun.misc.Launcher$ExtClassLoader@17d10166
用户自己类加载器,返回结果:sun.misc.Launcher$AppClassLoader@18b4aac2;result=sun.misc.Launcher$AppClassLoader@18b4aac2
-----------
bootstrapLoader为c++实现,所以返回结果为null;result=null
appClassLoader的父类加载器为extClassLoader;result=sun.misc.Launcher$ExtClassLoader@17d10166
SystemClassLoader默认就是appClassLoader,就是我们说的默认类加载器;result=sun.misc.Launcher$AppClassLoader@18b4aac2
-----------
打印bootstrapLoader加载的文件
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/resources.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/rt.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/sunrsasign.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/jsse.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/jce.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/charsets.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/jfr.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/classes
-----------
打印extstrapLoader加载的文件
/Users/dolphin/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java
-----------
打印appstrapLoader加载的文件
/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/lib/tools.jar:/Users/dolphin/goodfuture/selfproject/SpringBootTest/target/classes:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-starter/2.3.2.RELEASE/spring-boot-starter-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot/2.3.2.RELEASE/spring-boot-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/spring-context/5.2.8.RELEASE/spring-context-5.2.8.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-autoconfigure/2.3.2.RELEASE/spring-boot-autoconfigure-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-starter-logging/2.3.2.RELEASE/spring-boot-starter-logging-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/apache/logging/log4j/log4j-to-slf4j/2.13.3/log4j-to-slf4j-2.13.3.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/apache/logging/log4j/log4j-api/2.13.3/log4j-api-2.13.3.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/slf4j/jul-to-slf4j/1.7.30/jul-to-slf4j-1.7.30.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/spring-core/5.2.8.RELEASE/spring-core-5.2.8.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/spring-jcl/5.2.8.RELEASE/spring-jcl-5.2.8.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/yaml/snakeyaml/1.26/snakeyaml-1.26.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/cloud/spring-cloud-starter-alibaba-nacos-discovery/2.2.5.RELEASE/spring-cloud-starter-alibaba-nacos-discovery-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/cloud/spring-cloud-alibaba-commons/2.2.5.RELEASE/spring-cloud-alibaba-commons-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/nacos/nacos-client/1.4.1/nacos-client-1.4.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/nacos/nacos-common/1.4.1/nacos-common-1.4.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/commons-io/commons-io/2.2/commons-io-2.2.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/apache/httpcomponents/httpasyncclient/4.1.4/httpasyncclient-4.1.4.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/apache/httpcomponents/httpcore/4.4.13/httpcore-4.4.13.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/apache/httpcomponents/httpcore-nio/4.4.13/httpcore-nio-4.4.13.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/nacos/nacos-api/1.4.1/nacos-api-1.4.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/google/guava/guava/29.0-jre/guava-29.0-jre.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/checkerframework/checker-qual/2.11.1/checker-qual-2.11.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/google/errorprone/error_prone_annotations/2.3.4/error_prone_annotations-2.3.4.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/commons-codec/commons-codec/1.14/commons-codec-1.14.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/fasterxml/jackson/core/jackson-core/2.11.1/jackson-core-2.11.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/fasterxml/jackson/core/jackson-databind/2.11.1/jackson-databind-2.11.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/fasterxml/jackson/core/jackson-annotations/2.11.1/jackson-annotations-2.11.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/prometheus/simpleclient/0.5.0/simpleclient-0.5.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/spring/spring-context-support/1.0.10/spring-context-support-1.0.10.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/cloud/spring-cloud-commons/2.2.5.RELEASE/spring-cloud-commons-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/security/spring-security-crypto/5.3.3.RELEASE/spring-security-crypto-5.3.3.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/cloud/spring-cloud-context/2.2.5.RELEASE/spring-cloud-context-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/cloud/spring-cloud-starter-netflix-ribbon/2.2.5.RELEASE/spring-cloud-starter-netflix-ribbon-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/cloud/spring-cloud-netflix-ribbon/2.2.5.RELEASE/spring-cloud-netflix-ribbon-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/cloud/spring-cloud-netflix-archaius/2.2.5.RELEASE/spring-cloud-netflix-archaius-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/cloud/spring-cloud-starter-netflix-archaius/2.2.5.RELEASE/spring-cloud-starter-netflix-archaius-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/commons-configuration/commons-configuration/1.8/commons-configuration-1.8.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/ribbon/ribbon/2.3.0/ribbon-2.3.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/ribbon/ribbon-transport/2.3.0/ribbon-transport-2.3.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/reactivex/rxnetty-contexts/0.4.9/rxnetty-contexts-0.4.9.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/reactivex/rxnetty-servo/0.4.9/rxnetty-servo-0.4.9.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/javax/inject/javax.inject/1/javax.inject-1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/reactivex/rxnetty/0.4.9/rxnetty-0.4.9.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/ribbon/ribbon-core/2.3.0/ribbon-core-2.3.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/commons-lang/commons-lang/2.6/commons-lang-2.6.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/ribbon/ribbon-httpclient/2.3.0/ribbon-httpclient-2.3.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/apache/httpcomponents/httpclient/4.5.12/httpclient-4.5.12.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/sun/jersey/jersey-client/1.19.1/jersey-client-1.19.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/sun/jersey/jersey-core/1.19.1/jersey-core-1.19.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/javax/ws/rs/jsr311-api/1.1.1/jsr311-api-1.1.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/sun/jersey/contribs/jersey-apache-client4/1.19.1/jersey-apache-client4-1.19.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/servo/servo-core/0.12.21/servo-core-0.12.21.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/netflix-commons/netflix-commons-util/0.3.0/netflix-commons-util-0.3.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/ribbon/ribbon-loadbalancer/2.3.0/ribbon-loadbalancer-2.3.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/netflix-commons/netflix-statistics/0.1.1/netflix-statistics-0.1.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/reactivex/rxjava/1.3.8/rxjava-1.3.8.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/cloud/spring-cloud-starter-openfeign/2.2.5.RELEASE/spring-cloud-starter-openfeign-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/cloud/spring-cloud-starter/2.2.5.RELEASE/spring-cloud-starter-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/security/spring-security-rsa/1.0.9.RELEASE/spring-security-rsa-1.0.9.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/bouncycastle/bcpkix-jdk15on/1.64/bcpkix-jdk15on-1.64.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/bouncycastle/bcprov-jdk15on/1.64/bcprov-jdk15on-1.64.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/cloud/spring-cloud-openfeign-core/2.2.5.RELEASE/spring-cloud-openfeign-core-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-starter-aop/2.3.2.RELEASE/spring-boot-starter-aop-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/github/openfeign/form/feign-form-spring/3.8.0/feign-form-spring-3.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/github/openfeign/form/feign-form/3.8.0/feign-form-3.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/commons-fileupload/commons-fileupload/1.4/commons-fileupload-1.4.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/spring-web/5.2.8.RELEASE/spring-web-5.2.8.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/spring-beans/5.2.8.RELEASE/spring-beans-5.2.8.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/github/openfeign/feign-core/10.10.1/feign-core-10.10.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/github/openfeign/feign-slf4j/10.10.1/feign-slf4j-10.10.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/github/openfeign/feign-hystrix/10.10.1/feign-hystrix-10.10.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/archaius/archaius-core/0.7.6/archaius-core-0.7.6.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/netflix/hystrix/hystrix-core/1.5.18/hystrix-core-1.5.18.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/cloud/spring-cloud-starter-alibaba-nacos-config/2.2.5.RELEASE/spring-cloud-starter-alibaba-nacos-config-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/cloud/spring-cloud-starter-alibaba-sentinel/2.2.5.RELEASE/spring-cloud-starter-alibaba-sentinel-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-transport-simple-http/1.8.0/sentinel-transport-simple-http-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-transport-common/1.8.0/sentinel-transport-common-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-datasource-extension/1.8.0/sentinel-datasource-extension-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-annotation-aspectj/1.8.0/sentinel-annotation-aspectj-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-core/1.8.0/sentinel-core-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/aspectj/aspectjrt/1.9.6/aspectjrt-1.9.6.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/aspectj/aspectjweaver/1.9.6/aspectjweaver-1.9.6.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/cloud/spring-cloud-circuitbreaker-sentinel/2.2.5.RELEASE/spring-cloud-circuitbreaker-sentinel-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-reactor-adapter/1.8.0/sentinel-reactor-adapter-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-spring-webflux-adapter/1.8.0/sentinel-spring-webflux-adapter-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-spring-webmvc-adapter/1.8.0/sentinel-spring-webmvc-adapter-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-parameter-flow-control/1.8.0/sentinel-parameter-flow-control-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/googlecode/concurrentlinkedhashmap/concurrentlinkedhashmap-lru/1.4.2/concurrentlinkedhashmap-lru-1.4.2.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-cluster-server-default/1.8.0/sentinel-cluster-server-default-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-cluster-common-default/1.8.0/sentinel-cluster-common-default-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/csp/sentinel-cluster-client-default/1.8.0/sentinel-cluster-client-default-1.8.0.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/alibaba/cloud/spring-cloud-alibaba-sentinel-datasource/2.2.5.RELEASE/spring-cloud-alibaba-sentinel-datasource-2.2.5.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-starter-actuator/2.3.2.RELEASE/spring-boot-starter-actuator-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-actuator-autoconfigure/2.3.2.RELEASE/spring-boot-actuator-autoconfigure-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-actuator/2.3.2.RELEASE/spring-boot-actuator-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.11.1/jackson-datatype-jsr310-2.11.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/io/micrometer/micrometer-core/1.5.3/micrometer-core-1.5.3.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/hdrhistogram/HdrHistogram/2.1.12/HdrHistogram-2.1.12.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/latencyutils/LatencyUtils/2.0.3/LatencyUtils-2.0.3.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-starter-web/2.3.2.RELEASE/spring-boot-starter-web-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-starter-json/2.3.2.RELEASE/spring-boot-starter-json-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.11.1/jackson-datatype-jdk8-2.11.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.11.1/jackson-module-parameter-names-2.11.1.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/boot/spring-boot-starter-tomcat/2.3.2.RELEASE/spring-boot-starter-tomcat-2.3.2.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.37/tomcat-embed-core-9.0.37.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/glassfish/jakarta.el/3.0.3/jakarta.el-3.0.3.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.37/tomcat-embed-websocket-9.0.37.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/spring-webmvc/5.2.8.RELEASE/spring-webmvc-5.2.8.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/spring-aop/5.2.8.RELEASE/spring-aop-5.2.8.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/springframework/spring-expression/5.2.8.RELEASE/spring-expression-5.2.8.RELEASE.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/projectlombok/lombok/1.18.20/lombok-1.18.20.jar:/Users/dolphin/goodfuture/soft/apache-maven-3.8.1/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar
*/
}
何为双亲委派?
以下图来解释说明:当加载一个类的时候,先由应用程序类加载器向扩展类加载器发出请求,看看扩展类加载器中有没有要加载的类,如果有则返回,没有则继续向引导类加载器发出请求,看看引导类加载器中有没有要加载的类,如果有则返回,没有则将查找的任务交给请求方,一直到应用类加载器,如果依旧不存在,则报错。
双亲委派的作用
- 沙箱安全:如果自己写了一个和引导类一模一样的类,那么只会加载系统的,保证系统安全性
- 避免重复加载
其实在这里我们也可以猜测一下,为什么要从应用程序类加载器作为开始,而不是由引导类加载程序开始?
我觉得1.大牛就是这样设计的;2.我觉得90%都是运行自己的代码,所以除了第一次做一次查询外,其它时间都是直接在应用程序类加载器中实现了,毕竟一个系统,大部分都是我们自己写的代码
自定义类加载器
自定义类加载器重点便是继承java.lang.ClassLoader类。该类有2个核心方法,一个是loadClass(String name,boolean resolve)实现了双亲委派机制,另一个就是findClass方法,用于我们寻找指定目录下的class文件。
步骤:
- 创建一个测试类LoaderPrint,用于类加载器查询并加载
- 创建一个继承了ClassLoader的测试类SelfLoader(SelfClassLoader),并重写了里面的findClass方法
- 在硬盘上随便找一个目录,并按照测试类LoaderPrint所属包路径,创建目录
- 编译文件,将LoaderPrint.class文件,丢进步骤3最终目录中
- 重命名LoaderPrint.java或者删除,执行查看效果(1.如果没有改变项目中该文件,那么按照双亲委派机制,会用应用程序类加载器来加载target/classes中对应的类文件)
代码如下:
文件1:
package com.jvm;
/**
* 描述
*
* @author
* @version 1.0
* @date 2022/05/17 23:17:23
*/
public class LoaderPrint {
//public static String msg = "这是硬盘中的文件";
public static String msg = "这是内存中的文件";
public void sout(){
System.out.println(msg);
}
}
文件2:
package com.jvm;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 描述
*
* @author
* @version 1.0
* @date 2022/05/17 23:01:02
*/
public class SelfClassLoader {
static class SelfLoader extends ClassLoader{
private String classPath;
public SelfLoader(String classPath){
this.classPath = classPath;
}
/**
* 将字节码文件输出到字节数组中
* @param name
* @return
* @throws Exception
*/
private byte[] loadByte(String name){
name = name.replaceAll("\\.","/");
String url =classPath+"/"+name+".class";
System.out.println("url = " + url);
try {
InputStream is = new FileInputStream(url);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int num = 0;
while ((num = is.read(buffer)) != -1) {
stream.write(buffer, 0, num);
}
return stream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 这个类在classLoader里面是空实现,所以我们这里是重点继承,并加以实现
* 根据字节数组生成class对象
* @param name
* @return
* @throws ClassNotFoundException
*/
protected Class<?> findClass(String name) throws ClassNotFoundException {
try{
byte[]data = loadByte(name);
System.out.println("name = " + name);
return defineClass(name,data,0,data.length);
}catch (Exception e){
throw new ClassNotFoundException();
}
}
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String loadPath = "/Users/dolphin/logs";
String classPath = "com.jvm.LoaderPrint";
SelfLoader selfLoader = new SelfLoader(loadPath);
Class clazz = selfLoader.loadClass(classPath);
Object o = clazz.newInstance();
Method method = clazz.getDeclaredMethod("sout",null);
method.invoke(o,null);
System.out.println(clazz.getClassLoader().getClass().getName());
}
遇见的问题:
将本地硬盘中class文件转换成Class对象,调用了方法
defineClass(String name, byte[] b, int off, int len),这里需要注意这个传入的字节数组,该方法最终会调用验证环节,即是否合法的class文件。本次由于我误操作导致传入的字节数组为空,报错魔法值错误
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 0 in class file com/jvm/LoaderPrint
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
at java.lang.ClassLoader.defineClass(ClassLoader.java:635)
at com.jvm.SelfClassLoader$SelfLoader.findClass(SelfClassLoader.java:50)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at com.jvm.SelfClassLoader.main(SelfClassLoader.java:61)
打破双亲委派
首先我们自己先创建一个java.lang.String类,并运行,看看效果。报错:
注意:如果你测试的时候,你其它类里面有使用到了String类,那么会提示你对应你用到的String里面的其它方法错误。
注:jdk是不允许你威胁到它核心库的。
错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application
就像tomcat一样,不同的项目,加载相同的jar包,仅仅是版本不同,怎么做到的,我们来实现一下。其实这个重点就是我们上面提到过的loadClass方法。
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) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
我们上述源码中ClassLoader中的方法复制过来重写其中方法:
注:注意Object是所有类的父类,所以这个还得由jvm来处理,我们没有权限操作,否则会报如下图2错
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) {
long t0 = System.nanoTime();
try {
//TODO 注意Object是所有类的父类,所以这个还得由jvm来处理,我们没有权限操作
if(!name.startsWith("com.jvm")){
c = this.getParent().loadClass(name);
}else{
c= findClass(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
}
执行报错:
java.io.FileNotFoundException: /Users/dolphin/logs/java/lang/Object.class (No such file or directory)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at com.jvm.SelfClassLoader$SelfLoader.loadByte(SelfClassLoader.java:33)
at com.jvm.SelfClassLoader$SelfLoader.findClass(SelfClassLoader.java:58)
at com.jvm.SelfClassLoader$SelfLoader.loadClass(SelfClassLoader.java:80)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at java.lang.ClassLoader.defineClass1(Native Method)