ClassLoader源码解析续
这一部分是ClassLoader核心部分,加载给定的数据成对应的类对象。
/**
* 由虚拟机调用,这是一个private方法,但我在ClassLoader源码中并未看到有地方调用
* 看名字及源码说明,是由虚拟机加载类的时候内部调用,百度查询估计是加载jdk类时
* 系统类加载器通过反射调用该方法(jdk类中有许多类似用法)
*/
private Class loadClassInternal(String name)
throws ClassNotFoundException
{
if (parallelLockMap == null) {
synchronized (this) {
return loadClass(name);
}
} else {
return loadClass(name);
}
}
// 根据安全域策略,检查包权限,同样,由虚拟机在加载一个类后调用
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() {
public Void run() {
//具体的实现,由SecurityManager的native方法实现
sm.checkPackageAccess(name.substring(0, i));
return null;
}
}, new AccessControlContext(new ProtectionDomain[] {pd}));
}
}
domains.add(pd);
}
/**
* 类加载真正实现方法,由子类自己实现
* 一般真正实现会调用下方defineClass()相关方法
*/
protected Class> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
/**
* 将字节数组转化为Class对象
* 已不推荐使用,其实现中的name=null,会直接抛出异常
* 由下方defineClass(String, byte[], int, int)代替
* @see #loadClass(String, boolean)
* @see #resolveClass(Class)
*/
@Deprecated
protected final Class> defineClass(byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(null, b, off, len, null);
}
/**
* 字节流转化为Java Class对象,也可以理解为将字节流转换成JVM字节码
* name是表示将对应的字节流转化为对应路径类名的类的JVM字节码
*
* 这其中涉及到了安全策略、保护域、权限等知识。
*
* @see #loadClass(String, boolean)
* @see #resolveClass(Class)
* @see java.security.CodeSource
* @see java.security.SecureClassLoader
*/
protected final Class> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError
{
//底层实现,查看下方对应方法
return defineClass(name, b, off, len, null);
}
/**
* 决定类对应的保护域
* name是类的全路径名
*/
private ProtectionDomain preDefineClass(String name,
ProtectionDomain pd)
{
//类名格式是否合法
if (!checkName(name))
throw new NoClassDefFoundError("IllegalName: " + name);
//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;
}
//这个方法作用:当类加载错误(字节数据格式错误等),尝试重新定义类(重新生成Class对象)
private Class defineTransformedClass(String name, byte[] b, int off, int len,
ProtectionDomain pd,
ClassFormatError cfe, String source)
throws ClassFormatError
{
ClassFileTransformer[] transformers =
ClassFileTransformer.getTransformers();
Class c = null;
if (transformers != null) {
for (ClassFileTransformer transformer : transformers) {
try {
//使用对应的转换器将对应字节流转换成相应(编码?)的字节流
//可能是对特定格式的字节流的处理?
byte[] tb = transformer.transform(b, off, len);
c = defineClass1(name, tb, 0, tb.length,
pd, source);
break;
} catch (ClassFormatError cfe2) {
// 该转换器无效,尝试下一个
}
}
}
// 最终失败,抛出异常
if (c == null)
throw cfe;
return c;
}
//给类设置签名,调用本地方法
private void postDefineClass(Class c, ProtectionDomain pd)
{
if (pd.getCodeSource() != null) {
Certificate certs[] = pd.getCodeSource().getCertificates();
if (certs != null)
setSigners(c, certs);
}
}
/**
* 加载对应类名Class
*/
protected final Class> defineClass(String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain)
throws ClassFormatError
{
//检查ClassLoader是否被初始化,未初始化抛出未初始化异常
//另外,设置相应保护域
protectionDomain = preDefineClass(name, protectionDomain);
Class c = null;
String source = defineClassSourceLocation(protectionDomain);
try {
//调用native方法生成class文件,native方法的具体实现与JVM相关
c = defineClass1(name, b, off, len, protectionDomain, source);
} catch (ClassFormatError cfe) {
//出错,尝试使用特定转换器,重新加载
c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,
source);
}
//设置签名
postDefineClass(c, protectionDomain);
return c;
}
/**
* 加载缓冲区类型数据的类
* 类似上方方法,只是Class数据来源不同
*/
protected final Class> defineClass(String name, java.nio.ByteBuffer b,
ProtectionDomain protectionDomain)
throws ClassFormatError
{
int len = b.remaining();
// 虚拟机内存,使用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);
Class c = null;
String source = defineClassSourceLocation(protectionDomain);
try {
c = defineClass2(name, b, b.position(), len, protectionDomain,
source);
} catch (ClassFormatError cfe) {
byte[] tb = new byte[len];
b.get(tb);
c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe,
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);
// 校验类名
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;
}