解释:
启动虚拟机 (C++负责创建) 【windows : bin/java.exe调用 jvm.dll Linux : java 调用 libjvm.so 】
创建一个引导类加载器实例 (C++实现)
C++ 调用Java代码,创建JVM启动器,实例sun.misc.Launcher 【这货由引导加载器负责加载创建其他类加载器】
sun.misc.Launcher.getLauncher() 获取运行类自己的加载器ClassLoader --> 是AppClassLoader
获取到ClassLoader后调用loadClass(“A”)方法加载运行的类A
加载完成执行A类的main方法
程序运行结束
JVM销毁
加载 ----> 验证 ----> 准备 ----> 解析 ----> 初始化 ----> 使用 ----> 卸载
谈及比较多的是前五个
加载:我们说jvm执行的java字节码,编译后在磁盘上,总得读取这个字节码文件吧 ,通过啥读 IO呗 , 所以第一步肯定是加载字节码文件。
验证:JVM总不能说读到啥就直接运行了吧,你外面有个A.class 里面是一堆JVM规范不认识的内容,也执行不了啊 。 符合JVM规范才能执行后续的步骤,所以第二步是 校验字节码文件的正确性。
准备:给类的静态变量分配内存,并赋予默认值。 我们的类里,可能会包含一些静态变量吧 。 比如 public static final int a = 12;
得给a分配个默认值 0 ,再比如 public static User user = new User();
给 static的变量 User分配内存,并赋默认值null (final修饰的常量,直接赋值)。
解析:这个地方不是很好理解, 解析是什么意思呢?将符号引用替换为直接引用。 符号引用 ? 直接引用? what ? 我们的类的静态方法,比如main方法,其实在Java中有个叫法 都是叫符号 。 这个阶段就会吧,一些静态方法(符号引用,比如刚才说的main方法)替换为指向数据所存内存的指针或者句柄等(直接引用)【找到具体在内存中的位置】。 这个就是静态链接过程(在类加载期间完成)。 动态链接是在程序运行期间完成的将符号引用替换为直接引用 (比如某个普通方法的调用)。
初始化:上面的步骤完事儿以后,这一步主要是对类的静态变量初始化为指定的值,执行静态代码块。 比如刚才第二步的 public static final int a = 12;
,第二步给static变量赋了默认值,这一步就该把12赋值给它了。 还有 static的 User public static User user = new User();
实例化User。
说明:主类在运行过程中如果使用到其它类,会逐步加载这些类。jar包或war包里的类不是一次性全部加载的,是使用到时才加载。
public class TestDynamicLoad {
static {
System.out.println("加载TestDynamicLoad类中的静态代码块");
}
public static void main(String[] args) {
new A();
System.out.println("执行main方法中的代码");
B b = null;//B不会加载,除非这里执行 new B()
}
}
class A{
static {
System.out.println("加载A类中的静态代码块");
}
public A(){
System.out.println("加载A类中的构造方法");
}
}
class B{
static {
System.out.println("加载B类中的静态代码块");
}
public B(){
System.out.println("加载B类中的构造方法");
}
}
执行结果:
加载TestDynamicLoad类中的静态代码块
加载A类中的静态代码块
加载A类中的构造方法
执行main方法中的代码
类加载器示例:
import com.sun.crypto.provider.DESKeyFactory;
import sun.misc.Launcher;
import java.net.URL;
public class TestJDKClassLoader {
public static void main(String[] args) {
System.out.println(String.class.getClassLoader());
System.out.println(DESKeyFactory.class.getClassLoader().getClass().getName());
System.out.println(TestJDKClassLoader.class.getClassLoader().getClass().getName());
System.out.println();
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
ClassLoader extClassloader = appClassLoader.getParent();
ClassLoader bootstrapLoader = extClassloader.getParent();
System.out.println("the bootstrapLoader : " + bootstrapLoader);
System.out.println("the extClassloader : " + extClassloader);
System.out.println("the appClassLoader : " + appClassLoader);
System.out.println("AppClassLoader的父类加载器为ExtClassLoader,ExtClassLoader的父类加载器为null,null并不代表ExtClassLoader没有父类加载器,而是 BootstrapClassLoader");
System.out.println();
System.out.println("JRE的lib目录下的核心类库,bootstrapLoader加载以下文件:");
URL[] urls = Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i]);
}
System.out.println();
System.out.println("JRE的lib目录下的ext扩展目录中的JAR类包,extClassloader加载以下文件:");
String[] extClassloaderStr = System.getProperty("java.ext.dirs").split(";");
for (String s : extClassloaderStr) {
System.out.println(s);
}
System.out.println();
System.out.println("加载ClassPath路径下的类包,appClassLoader加载以下文件:");
String[] split = System.getProperty("java.class.path").split(";");
for (String s : split) {
System.out.println(s);
}
}
}
执行结果:
null
sun.misc.Launcher$ExtClassLoader
sun.misc.Launcher$AppClassLoader
the bootstrapLoader : null
the extClassloader : sun.misc.Launcher$ExtClassLoader@3dd3bcd
the appClassLoader : sun.misc.Launcher$AppClassLoader@14dad5dc
AppClassLoader的父类加载器为ExtClassLoader,ExtClassLoader的父类加载器为null,null并不代表ExtClassLoader没有父类加载器,而是 BootstrapClassLoader
JRE的lib目录下的核心类库,bootstrapLoader加载以下文件:
file:/D:/Environment/JDK/lib/resources.jar
file:/D:/Environment/JDK/lib/rt.jar
file:/D:/Environment/JDK/lib/sunrsasign.jar
file:/D:/Environment/JDK/lib/jsse.jar
file:/D:/Environment/JDK/lib/jce.jar
file:/D:/Environment/JDK/lib/charsets.jar
file:/D:/Environment/JDK/lib/jfr.jar
file:/D:/Environment/JDK/classes
JRE的lib目录下的ext扩展目录中的JAR类包,extClassloader加载以下文件:
D:\Environment\JDK\lib\ext
C:\Windows\Sun\Java\lib\ext
加载ClassPath路径下的类包,appClassLoader加载以下文件:
D:\Environment\JDK\jre\lib\charsets.jar
D:\Environment\JDK\jre\lib\deploy.jar
D:\Environment\JDK\jre\lib\ext\access-bridge-64.jar
D:\Environment\JDK\jre\lib\ext\cldrdata.jar
D:\Environment\JDK\jre\lib\ext\dnsns.jar
D:\Environment\JDK\jre\lib\ext\jaccess.jar
D:\Environment\JDK\jre\lib\ext\jfxrt.jar
D:\Environment\JDK\jre\lib\ext\localedata.jar
D:\Environment\JDK\jre\lib\ext\nashorn.jar
D:\Environment\JDK\jre\lib\ext\sunec.jar
D:\Environment\JDK\jre\lib\ext\sunjce_provider.jar
D:\Environment\JDK\jre\lib\ext\sunmscapi.jar
D:\Environment\JDK\jre\lib\ext\sunpkcs11.jar
D:\Environment\JDK\jre\lib\ext\zipfs.jar
D:\Environment\JDK\jre\lib\javaws.jar
D:\Environment\JDK\jre\lib\jce.jar
D:\Environment\JDK\jre\lib\jfr.jar
D:\Environment\JDK\jre\lib\jfxswt.jar
D:\Environment\JDK\jre\lib\jsse.jar
D:\Environment\JDK\jre\lib\management-agent.jar
D:\Environment\JDK\jre\lib\plugin.jar
D:\Environment\JDK\jre\lib\resources.jar
D:\Environment\JDK\jre\lib\rt.jar
D:\Project\Personal\website\reception\target\classes
D:\Environment\RepMaven\org\springframework\boot\spring-boot-starter\2.2.6.RELEASE\spring-boot-starter-2.2.6.RELEASE.jar
D:\Environment\RepMaven\org\springframework\boot\spring-boot\2.2.6.RELEASE\spring-boot-2.2.6.RELEASE.jar
D:\Environment\RepMaven\org\springframework\spring-context\5.2.5.RELEASE\spring-context-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\boot\spring-boot-autoconfigure\2.2.6.RELEASE\spring-boot-autoconfigure-2.2.6.RELEASE.jar
D:\Environment\RepMaven\org\springframework\boot\spring-boot-starter-logging\2.2.6.RELEASE\spring-boot-starter-logging-2.2.6.RELEASE.jar
D:\Environment\RepMaven\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar
D:\Environment\RepMaven\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar
D:\Environment\RepMaven\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar
D:\Environment\RepMaven\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar
D:\Environment\RepMaven\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar
D:\Environment\RepMaven\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar
D:\Environment\RepMaven\org\springframework\spring-core\5.2.5.RELEASE\spring-core-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\spring-jcl\5.2.5.RELEASE\spring-jcl-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar
D:\Environment\RepMaven\org\springframework\boot\spring-boot-starter-web\2.2.6.RELEASE\spring-boot-starter-web-2.2.6.RELEASE.jar
D:\Environment\RepMaven\org\springframework\boot\spring-boot-starter-json\2.2.6.RELEASE\spring-boot-starter-json-2.2.6.RELEASE.jar
D:\Environment\RepMaven\com\fasterxml\jackson\core\jackson-databind\2.10.3\jackson-databind-2.10.3.jar
D:\Environment\RepMaven\com\fasterxml\jackson\core\jackson-core\2.10.3\jackson-core-2.10.3.jar
D:\Environment\RepMaven\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.3\jackson-datatype-jdk8-2.10.3.jar
D:\Environment\RepMaven\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.3\jackson-datatype-jsr310-2.10.3.jar
D:\Environment\RepMaven\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.3\jackson-module-parameter-names-2.10.3.jar
D:\Environment\RepMaven\org\springframework\boot\spring-boot-starter-validation\2.2.6.RELEASE\spring-boot-starter-validation-2.2.6.RELEASE.jar
D:\Environment\RepMaven\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar
D:\Environment\RepMaven\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar
D:\Environment\RepMaven\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar
D:\Environment\RepMaven\org\springframework\spring-web\5.2.5.RELEASE\spring-web-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\spring-beans\5.2.5.RELEASE\spring-beans-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\spring-webmvc\5.2.5.RELEASE\spring-webmvc-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\spring-aop\5.2.5.RELEASE\spring-aop-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\spring-expression\5.2.5.RELEASE\spring-expression-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\apache\tomcat\embed\tomcat-embed-core\9.0.33\tomcat-embed-core-9.0.33.jar
D:\Environment\RepMaven\org\apache\tomcat\embed\tomcat-embed-el\9.0.33\tomcat-embed-el-9.0.33.jar
D:\Environment\RepMaven\org\apache\tomcat\embed\tomcat-embed-jasper\9.0.33\tomcat-embed-jasper-9.0.33.jar
D:\Environment\RepMaven\org\eclipse\jdt\ecj\3.18.0\ecj-3.18.0.jar
D:\Environment\RepMaven\jstl\jstl\1.2\jstl-1.2.jar
D:\Environment\RepMaven\mysql\mysql-connector-java\5.1.47\mysql-connector-java-5.1.47.jar
D:\Environment\RepMaven\tk\mybatis\mapper-spring-boot-starter\2.1.5\mapper-spring-boot-starter-2.1.5.jar
D:\Environment\RepMaven\org\springframework\boot\spring-boot-starter-jdbc\2.2.6.RELEASE\spring-boot-starter-jdbc-2.2.6.RELEASE.jar
D:\Environment\RepMaven\com\zaxxer\HikariCP\3.4.2\HikariCP-3.4.2.jar
D:\Environment\RepMaven\org\springframework\spring-jdbc\5.2.5.RELEASE\spring-jdbc-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\mybatis\mybatis\3.4.6\mybatis-3.4.6.jar
D:\Environment\RepMaven\org\mybatis\mybatis-spring\1.3.2\mybatis-spring-1.3.2.jar
D:\Environment\RepMaven\tk\mybatis\mapper-core\1.1.5\mapper-core-1.1.5.jar
D:\Environment\RepMaven\javax\persistence\persistence-api\1.0\persistence-api-1.0.jar
D:\Environment\RepMaven\tk\mybatis\mapper-base\1.1.5\mapper-base-1.1.5.jar
D:\Environment\RepMaven\tk\mybatis\mapper-weekend\1.1.5\mapper-weekend-1.1.5.jar
D:\Environment\RepMaven\tk\mybatis\mapper-spring\1.1.5\mapper-spring-1.1.5.jar
D:\Environment\RepMaven\tk\mybatis\mapper-extra\1.1.5\mapper-extra-1.1.5.jar
D:\Environment\RepMaven\tk\mybatis\mapper-spring-boot-autoconfigure\2.1.5\mapper-spring-boot-autoconfigure-2.1.5.jar
D:\Environment\RepMaven\com\alibaba\druid-spring-boot-starter\1.1.10\druid-spring-boot-starter-1.1.10.jar
D:\Environment\RepMaven\com\alibaba\druid\1.1.10\druid-1.1.10.jar
D:\Environment\RepMaven\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar
D:\Environment\RepMaven\org\mybatis\generator\mybatis-generator-core\1.3.3\mybatis-generator-core-1.3.3.jar
D:\Environment\RepMaven\io\springfox\springfox-swagger2\2.7.0\springfox-swagger2-2.7.0.jar
D:\Environment\RepMaven\io\swagger\swagger-annotations\1.5.13\swagger-annotations-1.5.13.jar
D:\Environment\RepMaven\io\swagger\swagger-models\1.5.13\swagger-models-1.5.13.jar
D:\Environment\RepMaven\com\fasterxml\jackson\core\jackson-annotations\2.10.3\jackson-annotations-2.10.3.jar
D:\Environment\RepMaven\io\springfox\springfox-spi\2.7.0\springfox-spi-2.7.0.jar
D:\Environment\RepMaven\io\springfox\springfox-core\2.7.0\springfox-core-2.7.0.jar
D:\Environment\RepMaven\net\bytebuddy\byte-buddy\1.10.8\byte-buddy-1.10.8.jar
D:\Environment\RepMaven\io\springfox\springfox-schema\2.7.0\springfox-schema-2.7.0.jar
D:\Environment\RepMaven\io\springfox\springfox-swagger-common\2.7.0\springfox-swagger-common-2.7.0.jar
D:\Environment\RepMaven\io\springfox\springfox-spring-web\2.7.0\springfox-spring-web-2.7.0.jar
D:\Environment\RepMaven\org\reflections\reflections\0.9.11\reflections-0.9.11.jar
D:\Environment\RepMaven\org\javassist\javassist\3.21.0-GA\javassist-3.21.0-GA.jar
D:\Environment\RepMaven\com\google\guava\guava\18.0\guava-18.0.jar
D:\Environment\RepMaven\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar
D:\Environment\RepMaven\org\springframework\plugin\spring-plugin-core\1.2.0.RELEASE\spring-plugin-core-1.2.0.RELEASE.jar
D:\Environment\RepMaven\org\springframework\plugin\spring-plugin-metadata\1.2.0.RELEASE\spring-plugin-metadata-1.2.0.RELEASE.jar
D:\Environment\RepMaven\org\mapstruct\mapstruct\1.1.0.Final\mapstruct-1.1.0.Final.jar
D:\Environment\RepMaven\io\springfox\springfox-swagger-ui\2.7.0\springfox-swagger-ui-2.7.0.jar
D:\Environment\RepMaven\org\projectlombok\lombok\1.18.12\lombok-1.18.12.jar
D:\Environment\RepMaven\redis\clients\jedis\3.1.0\jedis-3.1.0.jar
D:\Environment\RepMaven\org\apache\commons\commons-pool2\2.7.0\commons-pool2-2.7.0.jar
D:\Environment\RepMaven\org\springframework\boot\spring-boot-starter-amqp\2.2.6.RELEASE\spring-boot-starter-amqp-2.2.6.RELEASE.jar
D:\Environment\RepMaven\org\springframework\spring-messaging\5.2.5.RELEASE\spring-messaging-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\amqp\spring-rabbit\2.2.5.RELEASE\spring-rabbit-2.2.5.RELEASE.jar
D:\Environment\RepMaven\com\rabbitmq\amqp-client\5.7.3\amqp-client-5.7.3.jar
D:\Environment\RepMaven\org\springframework\amqp\spring-amqp\2.2.5.RELEASE\spring-amqp-2.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\retry\spring-retry\1.2.5.RELEASE\spring-retry-1.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\spring-tx\5.2.5.RELEASE\spring-tx-5.2.5.RELEASE.jar
D:\Environment\RepMaven\org\springframework\boot\spring-boot-configuration-processor\2.2.4.RELEASE\spring-boot-configuration-processor-2.2.4.RELEASE.jar
E:\SoftWare\IntelliJ IDEA 2019.1.1\lib\idea_rt.jar
C:\Users\root\.IntelliJIdea2019.1\system\captureAgent\debugger-agent.jar
什么是双亲委派机制?
为什么要设计双亲委派机制?
应用程序类加载器AppClassLoader加载类的双亲委派机制源码
private final ClassLoader parent;
protected Class> loadClass(String name, boolean resolve)throws ClassNotFoundException{
synchronized (getClassLoadingLock(name)) {
// 首先,检查请求的类是否已经被加载过
Class> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//父加载器不为空,调用父加载器loadClass()方法处理
c = parent.loadClass(name, false);
} else {
//父加载器为空,使用启动类加载器 BootstrapClassLoader 加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//抛出异常说明父类加载器无法完成加载请求
}
if (c == null) {
long t1 = System.nanoTime();
//自己尝试加载
c = findClass(name);
// 这是定义类装入器;记录统计信息
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
执行步骤:
String类加载示例:
package java.lang;
/**
* Description: String used for 我自定义的String类
* Created by root on 2020/8/11 10:33
*/
public class String {
public static void main(String[] args) {
System.out.println("我自定义的String类");
}
}
执行结果:
错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application
分析:首先由于全限定类名java.lang.String等于jdk中的String类,当AppClassLoader加载该String时,判断java.lang.String已经加载,便不会再次加载。所以执行的依旧是jdk中的String,但是系统的java.lang.String中没有main()方法,所以会报错。这是一种安全机制。
全盘负责委托机制,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
双亲委派机制,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效