源码解析
我们的应用类加载器和扩展类加载器都是在Launcher类中进行初始化的
public Launcher() {应用型加载器和扩展类加载器初始化
Launcher.ExtClassLoader var1;
try {
// 创建ExtClassLoader
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
// 创建AppClassLoader
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
// 设置上下文加载器为AppClassLoader,这里就可以解释为什么我们getContextClassLoader的时候为什么是AppClassLoader加载器了
Thread.currentThread().setContextClassLoader(this.loader);
String var2 = System.getProperty("java.security.manager");
if (var2 != null) {
SecurityManager var3 = null;
if (!"".equals(var2) && !"default".equals(var2)) {
try {
var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
} catch (IllegalAccessException var5) {
} catch (InstantiationException var6) {
} catch (ClassNotFoundException var7) {
} catch (ClassCastException var8) {
}
} else {
var3 = new SecurityManager();
}
if (var3 == null) {
throw new InternalError("Could not create SecurityManager: " + var2);
}
System.setSecurityManager(var3);
}
}
我们详解4个方法,这些方法都是在抽象类ClassLoader里面
loadClass():真正双亲委派机制的代码实现
findClass():查找二进制名称为name的类,返回结果为java.lang.Class类的实例。这是一个受保护的方法, JVM鼓励我们重写此方法,需要自定义加载器遵循双亲委托机制,该方法会在检查完父类加载器之后被loadClass()方法调用。
// 该方法在ClassLoader中是一个空方法,真正的实现实在URLClassLoader中
protected Class<?> findClass(final String name)defineClass():根据给定的字节数组b转换为Class的实例,off 和1en参数表示实际Class信息在byte数组中的位置和长度,其中byte数组b是ClassLoader从外部获取的。这是受保护的方法,只有在自定义ClassLoader子类中可以使用。
protected final Class<?> defineClass(String name, byte[] b, int off, int len, CodeSource cs)resolveClass():解析类
// resolve判断是否需要解析AppClassLoader中的loadclass
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 检查是否被加载过,如果没有被加载就返回null
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) {
}
// 如果没有被父级加载就开始加载
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;
}
}
SecureClassLoader和URLClassLoader
接着SecureClassLoader扩展了ClassLoader, 新增了几个与使用相关的代码源(对代码源的位置及其证书的验证)和权限定义类验证(主要指对class源码的访问权限)的方法,一 般我们不会直接跟这个类打交道,更多是与它的子类URLClassLoader有所关联。
前面说过,ClassLoader是一个抽象类,很多方法是空的没有实现,比如findClass()、findResource()等。而URLClassLoader这个实现类为这些方法提供了具体的实现。并新增了URLClassPath类协助取得Class字节码流等功能。在编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URLClassLoader类, 这样就可以避免自己去编写findClass()方法及其获取字节码流的方式,使自定义类加载器编写更加简洁。
Class.forName() 与ClassLoader.loadClass():
Class.forName():是一个静态方法,最常用的是Class.forName(String className) ;根据传入的类的全限定名返回一个Class对象。该方法在将Class文件加载到内存的同时,会执行类的初始化。如:Class.forName("com.atguigu.java.HelloWorld");
ClassLoader.loadClass(): 这是一个实例方法,需要一个ClassLoader 对象来调用该方法。该方法将Class文件加载到内存时,并不会执行类的初始化,直到这个类第一次使用时才进行初始化。该方法因为需要得到一个ClassLoader 对象,所以可以根据需要指定使用哪个类加载器.如: ClassLoader c1=.......; c1.loadClass("com.atguigu.java.HelloWorld");


雷达卡


京公网安备 11010802022788号







