JVM类加载
Posted wod-y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM类加载相关的知识,希望对你有一定的参考价值。
JVM class文件格式
- 魔法数 CAFE BABE
- 编译器版本号
- Constant count
- Constant pool
- access flag
- this class
- super class
- interface count
- interfaces
- field count
- fields
- method count
- methods
- attribute count
- attributes
源码:User.java
package com.wod.dao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class User {
@Value("lisi")
String username;
String password;
}
class:User.class
Classfile /d:/work/develop/juc_test/target/classes/com/wod/dao/User.class
Last modified 2020-6-20; size 562 bytes
MD5 checksum 27726ee8ded9222615d43ded38db4561
Compiled from "User.java"
public class com.wod.dao.User
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #2 // com/wod/dao/User
#2 = Utf8 com/wod/dao/User
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 username
#6 = Utf8 Ljava/lang/String;
#7 = Utf8 RuntimeVisibleAnnotations
#8 = Utf8 Lorg/springframework/beans/factory/annotation/Value;
#9 = Utf8 value
#10 = Utf8 lisi
#11 = Utf8 password
#12 = Utf8 <init>
#13 = Utf8 ()V
#14 = Utf8 Code
#15 = Methodref #3.#16 // java/lang/Object."<init>":()V
#16 = NameAndType #12:#13 // "<init>":()V
#17 = Utf8 LineNumberTable
#18 = Utf8 LocalVariableTable
#19 = Utf8 this
#20 = Utf8 Lcom/wod/dao/User;
#21 = Utf8 SourceFile
#22 = Utf8 User.java
#23 = Utf8 Lorg/springframework/stereotype/Component;
#24 = Utf8 Lorg/springframework/context/annotation/Scope;
#25 = Utf8 prototype
{
java.lang.String username;
descriptor: Ljava/lang/String;
flags:
RuntimeVisibleAnnotations:
0: #8(#9=s#10)
java.lang.String password;
descriptor: Ljava/lang/String;
flags:
public com.wod.dao.User();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #15 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 16: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/wod/dao/User;
}
SourceFile: "User.java"
RuntimeVisibleAnnotations:
0: #23()
1: #24(#9=s#25)
类加载过程
- loading:class文件通过类加载器加载到内存
- linking:验证class格式-》静态变量赋默认值-》将类、方法、属性等符号引用(常量池的引用)解析为直接引用
- initialing:类初始化,静态变量赋初始值
类加载器classloader
双亲委派机制
- 判断是否已加载:自定义加载器-》AppClassLoader-》ExtClassLoader-》BootStrapClassLoader(native)
- 依次尝试加载:BootStrapClassLoader-》ExtClassLoader-》AppClassLoader-》自定义加载器
体现双亲委派的代码
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;
}
热加载
- tomcat
- 双亲委派机制表示加载过就不再加载,所以需要自定义classloader重写loadClass打破双亲委派才能重新加载
public class SuccessedClassReloading2 {
private static class MyLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
File f = new File("D:/work/develop/juc_test/target/classes/" + name.replace(".", "/").concat(".class"));
if(!f.exists()) return super.loadClass(name);
try {
InputStream is = new FileInputStream(f);
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name, b, 0, b.length);
} catch (IOException e) {
e.printStackTrace();
}
return super.loadClass(name);
}
}
public static void main(String[] args) throws Exception {
MyLoader m = new MyLoader();
Class clazz = m.loadClass("com.wod.dao.User");
m = new MyLoader();
Class clazzNew = m.loadClass("com.wod.dao.User");
//false则表示重新加载成功
System.out.println(clazz == clazzNew);
}
}
以上是关于JVM类加载的主要内容,如果未能解决你的问题,请参考以下文章