0. 基本问题
//当前使用的classLoader
Thread.currentThread().getContextClassLoader(); //AppClassLoader
//jvm启动时设置setContextClassLoader
sun.misc.Launcher.Launcher()
//查看当前加载了哪些类
使用java安装目录下的jconsole.exe查看
1.加载器层次关系
bootStrap ClassLoader:加载基类,JAVA_HOME/lib或启动参数-Xbootclasspath指定的路径,按名识别rt.jar
扩展类加载器(Extension ClassLoader):加载JAVA_HOME/lib/ext/目录或系统变量java.ext.dirs指定路径的所有类库(开发可直接使用)。
AppClasLoader应用程序加载器(默认):ClassLoader.getSystemClassLoader()返回的值
2. 双亲委派模型--父类加载(非强制)
双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有字节的父类加载器,使用组合的方式(而不是继承)复用父加载器的代码。
工作过程:
一个类加载器收到了类加载请求,它首先不会自己尝试加载这个类,而是把这个请求委托给父类加载器取完成国内,所有加载请求最终都应该传送到顶层的BoootStrap加载器中,只有当父加载器无法完成这个加载请求(父搜索范围中没有找到所需的类),子加载器才尝试自己去加载。
好处:
保证类的唯一性,如类java.lang.Object,它存放在 rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加 载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类
实现-ClassLoader.loadClass:
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name); //是否已加载
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false); //使用父加载器进行加载
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
c = findClass(name); //附加载器无法完成时,自己加载
//自定义加载器时重写findClass方法即可
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
10. 自定义ClassLoader
1). 覆盖上下文的ClassLoader,Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);其它线程继承主进程的classloader,
Java加载类的过程,实质上是调用loadClass()方法,loadClass中调用findLoadedClass()方
法来检查该类是否已经被加载过,如果没有就会调用父加载器的loadClass(),如果父加载器
无法加载该类,就调用findClass()来查找该类。
2). 新建MyClassLoader继承java.lang.ClassLoader,重写其中的findClass()方法。主要是重新设计查找字节码文件的方案,然后调用definedClass来返回。