最近工作需要,要自己写一个自定义Classloader类。根据项目来讲一下Classloader 类相关内容。既然关于某某的内容,自然要有来源,道听途说的不要,直接上源码。这里源码主要用的是sun 的jdk,版本号是java 6。(其它版本,比如ibm 或者是oracle的不保证),另一部分是工作中遇到的问题。
好了,先讲一下java 内自带的几个主要的classcloader,一个是AppClassLoader,一个是ExtClassLoader,还有就是bootstrap class loader。前两个都在sun的Luncher 类内定义,都继承在URLClassLoader,而URLClassLoader 的祖先类便是大部分自定义类加载器要用到的ClassLoader类。AppClassLoader 也就是getSystemClassLoader获得的类。
AppclassLoader 的实现非常简单,使用了下securityManager就去调用ClassLoader 的loadClass 方法,这个方法,就是实现了所谓的双亲委派方式,先调一下父加载器,如果没有就去找boot strap 是不是加载了class,如果都没有,那么就自己加载。
那关键就是urlClassLoader,这个类主要是从url资源中(对于appclassloader就是classpath上资源)找到classname对应的class。这里插个题外话,对于appClassloader如果两个不过版本的jar出现的classpath,并且有重名名class会怎么样呢?分析下urlClassLoader 代码不能发现,结果是urlclassLoader 先找个哪个算哪个。囧了。
这些从代码上看过来的,在说一下项目里的问题,自己定义了一个classLoader 继承自ClassLoader 类,class 是直接是本地文件,不在classpath上。这个文件里包含三个class 类。一个外部类,两个内部类。一开始并没有把这个文件对应的java文件 去掉,老是报类重定义,去掉了,结果是一个内部类找不到。什么情况?类加载是通过classloader 独立进行的吗?classLoader不是可以当做命名空间来用吗?怎么看,这里显然是调了appclassloader。 看了下源码发现原来ClassLoader 类默认构造函数,会把appclassloader当父加载器设摄入
this(checkCreateClassLoader(), getSystemClassLoader());
}
而我的那个classLoader 也只实现了默认构造函数。那么自定义那个做不到类,自然会从父加载器加载,父加载器已经加载了,在加载同一个class 自然会报错。
好吧:
总结一下,第一,所有的classloader 都是出自ClassLoader类,如果你不想经过父加载器 和bootstrap,也可以重写loadClass方法(不建议)
第二,classloader 的调用是通过parent 进行的链式调用,要指定从哪一个环节开始,要在构造函数中显示指定。