自定义ClassLoader

自定义ClassLoader只要实现ClassLoader类的findClass()方法即可,要尽可能的避免覆盖loadClass()方法,因为在ClassLoader类里,loadClass()方法是实现了委托模型的,在自定义的ClassLoader方法中,可以通过ClassLoader的构造方法设定其parent成员变量,如果不设置,则默认为AppClassLoader,从ClassLoader的源代码可以看出:

protected ClassLoader(){
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
this.parent = getSystemClassLoader();
initialized = true;
}

那么当我们用自定义的ClassLoader,假如为MyClassLoader,当调用loadClass()来记载一个类的时候,会先尝试用MyClassLoader的parent AppClassLoader来加载这个类,AppClassLoader继续委托ExtClassLoader,ExtClassLoader继续委托BootstrapClassLoader,而最终到底谁来loadClass,则要看到底是在哪个ClassLoader所负责的加载路径下加载的该类,也就是findClass()到底是在哪find的该类,当然可以在MyClassLoader上定义自己的加载路径,具体定义就放在findClass()的实现方法里。

1:BootStrapClassLoader :加载java运行过程中的核心类库JRE\lib\rt.jar, sunrsasign.jar, charsets.jar, jce.jar, jsse.jar, plugin.jar 以及存放在JRE\classes里的类
2:ExtClassLoader :加载JRE\lib\ext 或者目录下的库文件目录下的类(包括任何子目录,有别于其他两个ClassLoader)
3:AppClassLoader :加载CLASSPATH变量指定路径下的类

A、其中AppClassLoader的parent(并非父类)为ExtClassLoader, ExtClassLoader的parent为BootStrapClassLoader,根据ClassLoader的委托模型,当要加载一个class时候会先让其parent来加载,如果parent找不到的话,再由自己来加载。
B、加载的第一个类的ClassLoader如果为BootStrapClassLoader的话,那么其他的所有类也必须又BootStrapClassLoader来加载,如果加载第一个类的ClassLoader为AppClassLoader的话,则类的加载按规则A来执行。

BootStrapClassLoader的默认Load路径可以通过 System.getProperty("sun.boot.class.path");来取得
ExtClassLoader的默认Load路径可以通过 System.getProperty("java.ext.dirs");来取得
AppClassLoader的默认Load路径可以通过 System.getProperty("java.class.path");来取得

其中ExtClassLoader,AppClassLoader的load可以通过命令:java -Djava.ext.dirs xxx xxx,java -Djava.class.path xxx xxx来改变
而BootStrapClassLoader的路径是用C++写死在JVM里面的,即使通过java -Dsun.boot.class.path xxx xxx来改变路径也不起任何作用。

没有评论: