上篇文章介绍到类加载器的双亲委派机制,但是jvm的类加载器为什么要采取这种的实现方式呢?
1.可以确保java核心类库的安全放着了jar包的冲突,例如所有的Java的应用可能都会使用java.lang.Object这个类,这个类是由启动类加载器加载的,如果他的子类加载器也加载了同样的类或者版本不一样的类可能就会产生冲突。
2.确保了Java的核心类不会被自定义的类所取代,假如自定了和核心类同名的类,可以保证这两个的隔离,从而不会被取代。
3.不同的类加载器可以为相同的类创建不同的命名空间从而是相同名字的两个类可以共存在jvm中。
接下来介绍一下三种类加载器的关系以及对其源码进行分析:
首先看下加载器的上层结构:
ExtClassLoader和AppClassLoader都继承自自URLClasssLoader,BootClassloader是用C++语言实现的(此处暂时不做分析),URLClassLoader:继承自SecureClassLoader,支持从jar文件和文件夹中获取class,继承于classload,加载时首先去classload里判断是否由bootstrap classload加载过,1.7 新增实现closeable接口,实现在try 中自动释放资源,但捕捉不了.close()异常
关于系统类加载器和扩展类加载器的实现都在sun.misc.Launcher这个类中,两个类都是Launcher的子类具体实现代码如下(方法实现已经省略):
static class AppClassLoader extends URLClassLoader {
public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
}
AppClassLoader(URL[] var1, ClassLoader var2) {
super(var1, var2, Launcher.factory);
}
public Class loadClass(String var1, boolean var2) throws ClassNotFoundException {
}
protected PermissionCollection getPermissions(CodeSource var1) {
}
private void appendToClassPathForInstrumentation(String var1) {
}
private static AccessControlContext getContext(File[] var0) throws MalformedURLException {
}
static {
ClassLoader.registerAsParallelCapable();
}
}
下面是扩展类加载器的实现:
static class ExtClassLoader extends URLClassLoader {
public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
}
void addExtURL(URL var1) {
}
public ExtClassLoader(File[] var1) throws IOException {
}
private static File[] getExtDirs() {
}
private static URL[] getExtURLs(File[] var0) throws IOException {
}
public String findLibrary(String var1) {
}
private static AccessControlContext getContext(File[] var0) throws IOException {
}
}
只有AppClassLoader重写了父类的loadClass方法,扩展类加载器是继承了父类的loadClass方法,在这个方法中都会实现双亲委派的逻辑:
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
同时在loadClass方法中会调用findLoadClass方法去判断是否该类被加载过,如果被加载过便不再被加载。
如果是自定义的类加载器我们去继承ClassLoader或者URLClassLoader都可以,然后重写其中的方法,在自定义类加载器后会默认加载父类加载器的无参构造方法,在其中会将AppClassLoader设置为自定义加载器的父类加载器,如果想自定义类的父类加载器需要显示指定构造方法:
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}