类加载小记

类加载的控制逻辑(loadClass): ——> java.lang.ClassLoader#loadClass

  • findLoadedClass // 检查是否已经被加载
  • loadClass // 使用parent class loader进行加载
  • findClass // 进行自定义的路径加载
  • resolveClass // 根据入参true或者false,进行动态链接。

线程默认类加载器:

  • AppClassLoader ——> 继承URLClassLoader
  • 双亲委派模式:AppClassLoader ——> ExtClassLoader ——> bootClassLoader

AppClassLoader的类层次结构:

  • ClassLoader
  • SecureClassLoader
  • URLClassLoader
  • AppClassLoader

类加载的关键方法:

  • loadClass // 定义加载的控制逻辑
  • findClass // 定义寻找的控制逻辑
  • defineClass // 将二进制数据转换成一个class对象

自定义类加载器举例:spring-boot-devtools#RestartClassLoader

  • 重写findClass、loadClass
  • 重写getResources、getResource、findResource

反序列化 VS 类加载:

(1) 类加载:二进制到class——> java.lang.ClassLoader#defineClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
将一个ByteBuffer转换成一个class
*/
protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,
ProtectionDomain protectionDomain)
throws ClassFormatError
{
int len = b.remaining();

// Use byte[] if not a direct ByteBufer:
if (!b.isDirect()) {
if (b.hasArray()) {
return defineClass(name, b.array(),
b.position() + b.arrayOffset(), len,
protectionDomain);
} else {
// no array, or read-only array
byte[] tb = new byte[len];
b.get(tb); // get bytes out of byte buffer.
return defineClass(name, tb, 0, len, protectionDomain);
}
}

protectionDomain = preDefineClass(name, protectionDomain);
String source = defineClassSourceLocation(protectionDomain);
// native 方法
Class<?> c = defineClass2(name, b, b.position(), len, protectionDomain, source);
postDefineClass(c, protectionDomain);
return c;
}

(2) 反序列化:类加载 + 实例化。

默认类加载器 ——> java.io.ObjectInputStream#resolveClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException
{
String name = desc.getName();
try {
// latestUserDefinedLoader() == AppClassLoader
return Class.forName(name, false, latestUserDefinedLoader());
} catch (ClassNotFoundException ex) {
Class<?> cl = primClasses.get(name);
if (cl != null) {
return cl;
} else {
throw ex;
}
}
}

配置自定义类加载器 ——> org.springframework.core#ConfigurableObjectInputStream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {
try {
if (this.classLoader != null) {
// Use the specified ClassLoader to resolve local classes.
return ClassUtils.forName(classDesc.getName(), this.classLoader);
}
else {
// Use the default ClassLoader...
return super.resolveClass(classDesc);
}
}
catch (ClassNotFoundException ex) {
return resolveFallbackIfPossible(classDesc.getName(), ex);
}
}