目录
  1. 1. ClassLoader源码解析
    1. 1.1. 类定义
    2. 1.2. 成员变量
    3. 1.3. 内部类
    4. 1.4. 构造方法
    5. 1.5. 主要方法
      1. 1.5.1. 类相关操作
        1. 1.5.1.1. loadClass
        2. 1.5.1.2. 虚拟机调用方法
        3. 1.5.1.3. findClass
        4. 1.5.1.4. defineClass
        5. 1.5.1.5. check
        6. 1.5.1.6. findSystemClass系统类加载
        7. 1.5.1.7. findBootstrapClassOrNull 根类加载
      2. 1.5.2. 资源相关操作
        1. 1.5.2.1. getResource
        2. 1.5.2.2. findResource
        3. 1.5.2.3. registerAsParallelCapable
        4. 1.5.2.4. getSystemResource
        5. 1.5.2.5. getBootstrapResource
        6. 1.5.2.6. 获取ClassPath或Stream
      3. 1.5.3. 层级相关操作
        1. 1.5.3.1. getParent
        2. 1.5.3.2. 获取类加载器
      4. 1.5.4. 包相关操作
ClassLoader源码解析

ClassLoader源码解析

类定义

  类加载器是负责加载类的对象.此类是一个抽象类.类加载程序应尝试查找或生成构成类定义的数据.典型的策略是将名称转换为文件名,然后从文件系统读取该名称的”类文件”
  每个对象包含GetClassLoader()引用以致于定义它的ClassLoader.
  数组类的对象不是由类加载器创建的,而是根据Java运行时的要求自动创建的.数组类的类加载器(由getClassLoader()返回)与其元素类型的类加载器相同;如果元素类型是基元类型,则数组类没有类加载器
  应用程序实现ClassLoader的子类,以扩展Java虚拟机动态加载类的方式
  安全管理器通常可以使用类加载器来指示安全域
  ClassLoader类使用委托模式搜索类和资源.ClassLoader的每个实例都有一个关联的父类加载器.当请求查找类或资源时,ClassLoader实例会将对类或资源的搜索委托给其父类加载器,然后再尝试查找类或资源本身.JVM的内置类加载器(称为”引导类加载器”)本身没有父级,但可以用作ClassLoader实例的父级
  支持类并发加载的类加载器称为”并行能力”类加载器,并且需要通过调用registerAsParallelCapable(ClassLoader.registerAsParallelCapable)方法在类初始化时注册自己.

请注意:ClassLoader类默认注册为支持并行.但是,如果子类具有并行功能,则仍需要自行注册.在委派模型不是严格分层的环境中,类加载器需要并行支持,否则类加载可能导致死锁,因为加载程序锁在类加载过程(loadClass)期间保持

  通常,Java虚拟机以平台相关的方式从本地文件系统加载类.例如:在Linux系统上,JVM从CLASSPATH环境变量定义的目录中加载类
  但是,有些类可能不是来自文件;它们可能来自其他来源,如网络或者可以由应用程序构造.方法fineClass(字符串、字节[]、int、int)fineClass将字节数组转换为类的实例.可以使用Class#newInstance创建这个新定义类的实例
  类加载器创建的对象的方法和构造函数可以引用其他类.为了确定所引用的类,JVM调用最初创建类的类加载器的loadClass方法
  例如,应用程序可以创建网络类加载器以从服务器下载类文件.示例代码可能如下所示:

1
2
ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();

  网络类加载程序子类必须定义findClass和加载类数据以便从网络加载类.下载组成类的字节后,应使用方法defineClass来创建类实例.示例实现是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class NetworkClassLoader extends ClassLoader {
String host;
int port;

public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}

private byte[] loadClassData(String name) {
// load the class data from the connection
 . . .
}
}

成员变量

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
// 用于委托的父类加载器
// 注意:VM对该字段的偏移量进行了硬编码,因此必须在这个字段添加所有新字段
private final ClassLoader parent;

// 当前类加载器具有并行功能时,将类名称映射到相应的锁对象
// 注意: 虚拟机还使用此字段来确定当前的类加载器是否具有并行功能,以及用于类加载的适当锁定对象
private final ConcurrentHashMap<String, Object> parallelLockMap;

// 将包映射到证书的哈希表
private final Map <String, Certificate[]> package2certs;

// 在所有未签名类的软件包中共享
private static final Certificate[] nocerts = new Certificate[0];

// 该类加载器加载的类.该表的唯一目的是防止对类进行GC处理,直到对加载程序进行GC处理为止
private final Vector<Class<?>> classes = new Vector<>();

// "默认"域.在新创建的类上设置为默认的ProtectionDomain
private final ProtectionDomain defaultDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null),null, this, null);

// 此加载器加载的所有类的初始保护域
private final Set<ProtectionDomain> domains;

// 在此类加载器中定义的包.每个包名称都映射到其相应的Package对象
// @GuardedBy("itself")
private final HashMap<String, Package> packages = new HashMap<>();

内部类

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
31
32
33
34
35
36
37
38
39
40
/**
* 封装一组并行的加载器类型
*/
private static class ParallelLoaders {
private ParallelLoaders() {}

// 可并行加载的类型的集合
private static final Set<Class<? extends ClassLoader>> loaderTypes =
Collections.newSetFromMap(new WeakHashMap<Class<? extends ClassLoader>, Boolean>());

static {
synchronized (loaderTypes) { loaderTypes.add(ClassLoader.class); }
}

/**
* 将给定的类加载器类型注册为具有并行功能
* 返回值: true是成功注册;false如果加载程序的超类未注册
*/
static boolean register(Class<? extends ClassLoader> c) {
synchronized (loaderTypes) {
if (loaderTypes.contains(c.getSuperclass())) {
// 当且仅当其所有父类都具有时,才将类加载器注册为并行功能
// 注意: 给定当前的类加载顺序,如果直接父类具有并行功能,那么所有更高级别的父类也必须具有并行能力
loaderTypes.add(c);
return true;
} else {
return false;
}
}
}

/**
* 返回值: true 如果给定的类加载器类型注册为具有并行功能
*/
static boolean isRegistered(Class<? extends ClassLoader> c) {
synchronized (loaderTypes) {
return loaderTypes.contains(c);
}
}
}

构造方法

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
31
private ClassLoader(Void unused, ClassLoader parent) {
this.parent = parent;
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
domains = Collections.synchronizedSet(new HashSet<ProtectionDomain>());
assertionLock = new Object();
} else {
// 没有更细粒度的锁定;锁定classloader实例
parallelLockMap = null;
package2certs = new Hashtable<>();
domains = new HashSet<>();
assertionLock = this;
}
}

/**
* 使用指定的父类加载器创建新的类加载器以进行委派
*
* 如果存在安全管理器,则调用其SecurityManager#checkCreateClassLoader()方法.这可能导致安全异常
*/
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}

/**
* 使用ClassLoader的getSystemClassLoader()作为父类加载器,创建新的类加载程序
*/
protected ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}

主要方法

1
2
3
4
5
6
7
8
9
10
11
12
// 虚拟机调用以使用此加载器记录每个加载的类。
void addClass(Class<?> c) {
classes.addElement(c);
}

private static Void checkCreateClassLoader() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
return null;
}

类相关操作

loadClass

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
* 使用指定的名称加载.
* 此方法与loadClass(字符串、布尔)方法相同的方式搜索类
* 由Java虚拟机调用它来解析类引用.调用此方法等效于调用loadClass(字符串、布尔)和loadClass(名称、false)
*/
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}

/**
* 使用指定的名称加载.此方法的默认实现按以下顺序搜索类:
* - 调用findLoadedClass(字符串)以检查类是否已加载
* - 在父类加载器上调用loadClass(字符串)方法.如果父级为空则改为使用根类加载器加载
* - 调用findClass(字符串)方法来查找类
*
* 如果使用上述步骤找到类,并且解析标志为true,则此方法将在生成的类对象上调用resolveClass(Class)方法
* 建议ClassLoader的子类重写findClass(字符串),而不是此方法
* 除非重写,否则此方法将在整个类加载过程中对getClassLoadingLock方法的结果进行同步
*/
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) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 如果从非空父类加载器中找不到类,则抛出ClassNotFoundException
}

if (c == null) {
// 如果仍然找不到,请调用findClass以便找到该类。
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;
}
}

/**
* 返回用于类加载操作的锁对象
* 为了向后兼容,此方法的默认实现如下所示.如果此ClassLoader对象注册为具有并行功能,则该方法返回与指定的类名关联的专用对象.否则该方法返回此ClassLoader对象
* @param className 待加载类的名称
* @return 类加载操作的锁
*/
protected Object getClassLoadingLock(String className) {
Object lock = this;
if (parallelLockMap != null) {
Object newLock = new Object();
lock = parallelLockMap.putIfAbsent(className, newLock);
if (lock == null) {
lock = newLock;
}
}
return lock;
}

虚拟机调用方法

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
31
32
33
34
35
36
// 虚拟机将调用此方法以加载类
private Class<?> loadClassInternal(String name) throws ClassNotFoundException {
// 为了向后兼容,当当前的类加载器不具有并行功能时,显式锁定"this"
if (parallelLockMap == null) {
synchronized (this) {
return loadClass(name);
}
} else {
return loadClass(name);
}
}

// 使用此加载器加载类后,由VM调用
private void checkPackageAccess(Class<?> cls, ProtectionDomain pd) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (ReflectUtil.isNonPublicProxyClass(cls)) {
for (Class<?> intf: cls.getInterfaces()) {
checkPackageAccess(intf, pd);
}
return;
}

final String name = cls.getName();
final int i = name.lastIndexOf('.');
if (i != -1) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
sm.checkPackageAccess(name.substring(0, i));
return null;
}
}, new AccessControlContext(new ProtectionDomain[] {pd}));
}
}
domains.add(pd);
}

findClass

1
2
3
4
5
6
7
8
/**
* 通过指定的名称查找类
* 此方法应该由遵循委派模型加载类的类加载器实现重写,并且将在检查请求类的父类加载程序后由loadClass方法调用此方法.
* 默认实现引发ClassNotFoundException
*/
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
* 将字节数组转换为Class的实例; 在使用Class之前,必须解析它.
*
* 此方法分配一个默认java.security.ProtectionDomain给新定义的类
* ProtectionDomain在调用java.security.policy#getPermissions(java.security.codeSource)被调用时,为ProtectionDomain授予了同一组权限
* 默认域在第一次调用defineClass(字符串、字节、int、int)时创建,并在后续调用时重复使用
*
* 要为类分配特定的ProtectionDomain,请使用defineClass(字符串、字节、int、int、java.Security.ProtectionDomain)方法,该方法采用ProtectionDomain作为其参数之一
*/
protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError {
return defineClass(name, b, off, len, null);
}

/**
* 使用可选的ProtectionDomain将字节数组转换为Class的实例
* 如果domain为空,则默认域将分配给defineClass(String、字节、int、int)文档中指定的类
* 在可以使用类之前,必须解析它
*/
protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) throws ClassFormatError {
protectionDomain = preDefineClass(name, protectionDomain);
String source = defineClassSourceLocation(protectionDomain);
Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
postDefineClass(c, protectionDomain);
return c;
}

/**
* 确定保护域,并检查:
* - 未定义java.*类
* - 此类的签名者与包中其余类的签名者匹配
*/
private ProtectionDomain preDefineClass(String name,ProtectionDomain pd) {
if (!checkName(name))
throw new NoClassDefFoundError("IllegalName: " + name);

// 注意:检查java.lang.invoke.MemberName.checkForTypeAlias中的逻辑依赖于以下事实:如果类的名称形式为" java。*",则不可能进行欺骗
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException("Prohibited package name: " + name.substring(0, name.lastIndexOf('.')));
}
if (pd == null) {
pd = defaultDomain;
}

if (name != null) checkCerts(name, pd.getCodeSource());

return pd;
}

private String defineClassSourceLocation(ProtectionDomain pd) {
CodeSource cs = pd.getCodeSource();
String source = null;
if (cs != null && cs.getLocation() != null) {
source = cs.getLocation().toString();
}
return source;
}

private void postDefineClass(Class<?> c, ProtectionDomain pd) {
if (pd.getCodeSource() != null) {
Certificate certs[] = pd.getCodeSource().getCertificates();
if (certs != null)
setSigners(c, certs);
}
}

/**
* 将ByteBuffer转换为Class的实例,并带有可选的ProtectionDomain
*/
protected final Class<?> defineClass(String name, java.nio.ByteBuffer b, ProtectionDomain protectionDomain) throws ClassFormatError {
int len = b.remaining();

// 如果不是直接的ByteBufer,请使用byte []:
if (!b.isDirect()) {
if (b.hasArray()) {
return defineClass(name, b.array(), b.position() + b.arrayOffset(), len, protectionDomain);
} else {
// 没有数组或只读数组
byte[] tb = new byte[len];
b.get(tb); // 从字节缓冲区中获取字节
return defineClass(name, tb, 0, len, protectionDomain);
}
}

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

private native Class<?> defineClass0(String name, byte[] b, int off, int len, ProtectionDomain pd);

private native Class<?> defineClass1(String name, byte[] b, int off, int len, ProtectionDomain pd, String source);

private native Class<?> defineClass2(String name, java.nio.ByteBuffer b, int off, int len, ProtectionDomain pd, String source);

check

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 如果名称为null或有可能成为有效的二进制名称,则为true
private boolean checkName(String name) {
if ((name == null) || (name.length() == 0))
return true;
if ((name.indexOf('/') != -1)
|| (!VM.allowArraySyntax() && (name.charAt(0) == '[')))
return false;
return true;
}

private void checkCerts(String name, CodeSource cs) {
int i = name.lastIndexOf('.');
String pname = (i == -1) ? "" : name.substring(0, i);

Certificate[] certs = null;
if (cs != null) {
certs = cs.getCertificates();
}
Certificate[] pcerts = null;
if (parallelLockMap == null) {
synchronized (this) {
pcerts = package2certs.get(pname);
if (pcerts == null) {
package2certs.put(pname, (certs == null? nocerts:certs));
}
}
} else {
pcerts = ((ConcurrentHashMap<String, Certificate[]>)package2certs).
putIfAbsent(pname, (certs == null? nocerts:certs));
}
if (pcerts != null && !compareCerts(pcerts, certs)) {
throw new SecurityException("class \""+ name +
"\"'s signer information does not match signer information of other classes in the same package");
}
}

/**
* 检查以确保新类的证书与插入到包中的第一个类的证书(pcerts)相同
*/
private boolean compareCerts(Certificate[] pcerts, Certificate[] certs) {
// certs可以为null,表示没有证书
if ((certs == null) || (certs.length == 0)) {
return pcerts.length == 0;
}

// 此时长度必须相同
if (certs.length != pcerts.length)
return false;

// 仔细检查并确保一个数组中的所有证书都在另一个数组中,反之亦然
boolean match;
for (int i = 0; i < certs.length; i++) {
match = false;
for (int j = 0; j < pcerts.length; j++) {
if (certs[i].equals(pcerts[j])) {
match = true;
break;
}
}
if (!match) return false;
}

// 现在对pcerts执行相同的操作
for (int i = 0; i < pcerts.length; i++) {
match = false;
for (int j = 0; j < certs.length; j++) {
if (pcerts[i].equals(certs[j])) {
match = true;
break;
}
}
if (!match) return false;
}

return true;
}

findSystemClass系统类加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 此方法通过系统类加载器加载类getSystemClassLoader()
* 返回的Class对象可能有多个ClassLoader与之关联.ClassLoader的子类通常不需要调用此方法,因为大多数类加载程序只需要重写findClass(String)
*/
protected final Class<?> findSystemClass(String name) throws ClassNotFoundException {
ClassLoader system = getSystemClassLoader();
if (system == null) {
if (!checkName(name))
throw new ClassNotFoundException(name);
Class<?> cls = findBootstrapClass(name);
if (cls == null) {
throw new ClassNotFoundException(name);
}
return cls;
}
return system.loadClass(name);
}

findBootstrapClassOrNull 根类加载

1
2
3
4
5
6
7
/**
* 返回由引导类加载器加载的类;或如果找不到则返回null
*/
private Class<?> findBootstrapClassOrNull(String name) {
if (!checkName(name)) return null;
return findBootstrapClass(name);
}

资源相关操作

getResource

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
31
32
33
34
35
/**
* 根据给定名称查找资源
* 资源是某些数据(图像、音频、文本等),可由类代码以与代码位置无关的方式进行访问
* 资源的名称是用'/'分隔的路径名,用于标识资源
*
* 此方法将首先在父类加载器中搜索资源;如果父级为空则搜索内置到虚拟机的类加载器的路径.如果失败,此方法将调用findResource(String)以查找资源
*/
public URL getResource(String name) {
URL url;
if (parent != null) {
url = parent.getResource(name);
} else {
url = getBootstrapResource(name);
}
if (url == null) {
url = findResource(name);
}
return url;
}

/**
* 查找具有给定名称的所有资源
*/
public Enumeration<URL> getResources(String name) throws IOException {
@SuppressWarnings("unchecked")
Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];
if (parent != null) {
tmp[0] = parent.getResources(name);
} else {
tmp[0] = getBootstrapResources(name);
}
tmp[1] = findResources(name);

return new CompoundEnumeration<>(tmp);
}

findResource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 查找具有给定名称的资源.类加载器的实现应重写此方法以指定在何处查找资源
*/
protected URL findResource(String name) {
return null;
}

/**
* 返回URL对象的枚举,该对象代表具有给定名称的所有资源.
* 类加载器实现应重写此方法以指定从何处加载资源。
*/
protected Enumeration<URL> findResources(String name) throws IOException {
return java.util.Collections.emptyEnumeration();
}

registerAsParallelCapable

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 将调用方注册为可并行处理.仅当满足以下所有条件时,注册成功:
* - 尚未创建调用者的实例
* - 调用者的所有父类(对象类除外)都注册为具有并行功能
* 注意:一旦将类加载器注册为具有并行功能,就无法将其改回
*/
@CallerSensitive
protected static boolean registerAsParallelCapable() {
Class<? extends ClassLoader> callerClass =
Reflection.getCallerClass().asSubclass(ClassLoader.class);
return ParallelLoaders.register(callerClass);
}

getSystemResource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 从用于加载类的搜索路径中查找指定名称的资源.此方法通过系统类加载器查找资源
*/
public static URL getSystemResource(String name) {
ClassLoader system = getSystemClassLoader();
if (system == null) {
return getBootstrapResource(name);
}
return system.getResource(name);
}

/**
* 从用于加载类的搜索路径中查找指定名称的所有资源
*/
public static Enumeration<URL> getSystemResources(String name) throws IOException {
ClassLoader system = getSystemClassLoader();
if (system == null) {
return getBootstrapResources(name);
}
return system.getResources(name);
}

getBootstrapResource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 从VM的内置类加载器中查找资源
*/
private static URL getBootstrapResource(String name) {
URLClassPath ucp = getBootstrapClassPath();
Resource res = ucp.getResource(name);
return res != null ? res.getURL() : null;
}

private static Enumeration<URL> getBootstrapResources(String name)
throws IOException {
final Enumeration<Resource> e =
getBootstrapClassPath().getResources(name);
return new Enumeration<URL> () {
public URL nextElement() {
return e.nextElement().getURL();
}
public boolean hasMoreElements() {
return e.hasMoreElements();
}
};
}

获取ClassPath或Stream

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
/**
* 返回用于查找系统资源的URLClassPath.
*/
static URLClassPath getBootstrapClassPath() {
return sun.misc.Launcher.getBootstrapClassPath();
}

/**
* 返回用于读取指定资源的输入流
*/
public InputStream getResourceAsStream(String name) {
URL url = getResource(name);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null;
}
}

/**
* 打开供读取,这是用于加载类的搜索路径中指定名称的资源.此方法通过系统类加载器查找资源
*/
public static InputStream getSystemResourceAsStream(String name) {
URL url = getSystemResource(name);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null;
}
}

层级相关操作

getParent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 返回用于委托的父类加载器
* 一些实现可能使用null表示引导类加载器.如果此类加载器的父级是引导类加载器,则此方法在此类实现中将返回null
*/
@CallerSensitive
public final ClassLoader getParent() {
if (parent == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// 检查对父类加载器的访问如果调用者的类加载器与此类加载器相同,则执行权限检查
checkClassLoaderPermission(parent, Reflection.getCallerClass());
}
return parent;
}

获取类加载器

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/**
* 返回用于委托的系统类加载器.这是新的ClassLoader实例的默认委派父级,通常是用于启动应用程序的类加载器
*/
@CallerSensitive
public static ClassLoader getSystemClassLoader() {
initSystemClassLoader();
if (scl == null) {
return null;
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkClassLoaderPermission(scl, Reflection.getCallerClass());
}
return scl;
}

private static synchronized void initSystemClassLoader() {
if (!sclSet) {
if (scl != null)
throw new IllegalStateException("recursive invocation");
sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
if (l != null) {
Throwable oops = null;
scl = l.getClassLoader();
try {
scl = AccessController.doPrivileged(
new SystemClassLoaderAction(scl));
} catch (PrivilegedActionException pae) {
oops = pae.getCause();
if (oops instanceof InvocationTargetException) {
oops = oops.getCause();
}
}
if (oops != null) {
if (oops instanceof Error) {
throw (Error) oops;
} else {
// 包装exception
throw new Error(oops);
}
}
}
sclSet = true;
}
}

/**
* 如果可以在此类加载器的委托链中找到指定的类加载器,则返回true
*/
boolean isAncestor(ClassLoader cl) {
ClassLoader acl = this;
do {
acl = acl.parent;
if (cl == acl) {
return true;
}
} while (acl != null);
return false;
}

/**
* 测试类加载器访问是否需要"getClassLoader"权限检查
* 如果类加载器"from"与类加载器"to"相同或父类是"to",则类加载器"from"可以访问类加载器"to".系统域中的类加载器可以访问任何类加载器
*/
private static boolean needsClassLoaderPermissionCheck(ClassLoader from, ClassLoader to) {
if (from == to)
return false;

if (from == null)
return false;

return !to.isAncestor(from);
}

// 返回类的类加载器;如果没有,则返回null
static ClassLoader getClassLoader(Class<?> caller) {
// 如果VM正在请求,则可以为null
if (caller == null) {
return null;
}
// 规避安全检查,因为这是包私有的
return caller.getClassLoader0();
}

/*
* 如果调用者的类加载器不为null且调用者的类加载器与给定cl参数的祖先不同,则检查RuntimePermission(" getClassLoader")权限
*/
static void checkClassLoaderPermission(ClassLoader cl, Class<?> caller) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// 如果VM请求,调用方可以为null
ClassLoader ccl = getClassLoader(caller);
if (needsClassLoaderPermissionCheck(ccl, cl)) {
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}

包相关操作

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
* 在此ClassLoader中通过名称定义一个包.
* 这允许类加载器为其类定义包.必须在定义类之前创建包,并且包名称在类加载器中必须唯一,并且一旦创建就不能重新定义或更改
*/
protected Package definePackage(String name, String specTitle,String specVersion, String specVendor,String implTitle, String implVersion,String implVendor, URL sealBase) throws IllegalArgumentException {
synchronized (packages) {
Package pkg = getPackage(name);
if (pkg != null) {
throw new IllegalArgumentException(name);
}
pkg = new Package(name, specTitle, specVersion, specVendor,
implTitle, implVersion, implVendor,
sealBase, this);
packages.put(name, pkg);
return pkg;
}
}

/**
* 返回由该类加载器或其任何祖先定义的Package
*/
protected Package getPackage(String name) {
Package pkg;
synchronized (packages) {
pkg = packages.get(name);
}
if (pkg == null) {
if (parent != null) {
pkg = parent.getPackage(name);
} else {
pkg = Package.getSystemPackage(name);
}
if (pkg != null) {
synchronized (packages) {
Package pkg2 = packages.get(name);
if (pkg2 == null) {
packages.put(name, pkg);
} else {
pkg = pkg2;
}
}
}
}
return pkg;
}

/**
* 返回此类加载器及其祖先定义的所有Packages
*/
protected Package[] getPackages() {
Map<String, Package> map;
synchronized (packages) {
map = new HashMap<>(packages);
}
Package[] pkgs;
if (parent != null) {
pkgs = parent.getPackages();
} else {
pkgs = Package.getSystemPackages();
}
if (pkgs != null) {
for (int i = 0; i < pkgs.length; i++) {
String pkgName = pkgs[i].getName();
if (map.get(pkgName) == null) {
map.put(pkgName, pkgs[i]);
}
}
}
return map.values().toArray(new Package[map.size()]);
}
文章作者: Eric Liang
文章链接: https://ericql.github.io/2019/11/12/01-Java%E5%9F%BA%E7%A1%80%E7%AF%87/02-JDK%E6%BA%90%E7%A0%81%E7%AF%87/ClassLoader%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Eric Liang
打赏
  • 微信
  • 支付宝