转载

对Java的ClassLoader的几点认识

1 ClassLoader只是一个普通抽象类,它的工作是从类名得到Class。ClassLoader与其他类的唯一不同之处是它是为JVM服务的,属于“公务员”,例如Thread就带有getContextClassLoader()和setContextClassLoader()方法;

2 ClassLoader的实现类URLClassLoader完成工作的方法是根据传入的class目录或jar文件的URL读取二进制文件,并转化为Class;

3 ClassLoader有个成员变量parent,使用ClassLoader获取Class时,默认会先用它的parent尝试获取该Class,没有的话自己再尝试。当然,你可以自己实现ClassLoader来改变这一行为。例如:

import java.net.URL; import java.net.URLClassLoader;  /**  * 先自己尝试获取Class,不行再找parent  */ public class OverridingClassLoader extends URLClassLoader {      private final ClassLoader parent;    public OverridingClassLoader(URL[] urls, ClassLoader parent)   {     super(urls, null);     this.parent = parent;   }    @Override   public Class<?> loadClass(String name) throws ClassNotFoundException   {     try     {       return super.loadClass(name);     } catch (Exception e)     {       return parent.loadClass(name);     }   }  }

4 JVM不会关心进程里有多少个ClassLoader实例,也不关心它们从各种途径读出来多少个Class,所以类名相同的Class可以同时存在多个。这会造成一些混乱,比如,假设两个类Person和Student有继承关系,并被一个ClassLoader读进了JVM,然后某个ClassLoader从另一个jar文件又读进来一个Person,这时第一个Student和第二个Person将没有任何关系,instanceof或isAssignableFrom均会返回false;

5 第三方库或框架比如Spring、Hadoop往往会尝试调用Thread.currentThread().getContextClassLoader()来获取ClassLoader为己用,所以你若是想要它们使用你的自定义ClassLoader,记得提前调用Thread.currentThread().setContextClassLoader()把你的ClassLoader设进去。Tomcat就是这么做的,每个webapp的Thread.currentThread().getContextClassLoader()都会返回与该webapp绑定的一个WebappClassLoader实例,所以使用不同jar包的webapp们不会互相影响。

正文到此结束
Loading...