tomcat阅读源码中涉及的知识点---自定义类加载器

tomcat 自定义类加载器,目的比较多。当前分析一个作用,隔离不同web应用中的代码。

隔离的原因比较多,比如有app1, app2两个应用,分别引用了1.0和1.1的common.jar包中的一个类VersionInfo。

其中,1.1版本的VersionInfo.java 多了一个方法,而这个方法正好被app1引用。

体现了冲突jar加载的冲突影响。 后面用自定义加载器,如何规避这种影响。


1.0版本的类

tomcat阅读源码中涉及的知识点---自定义类加载器


1.1 版本的类。

tomcat阅读源码中涉及的知识点---自定义类加载器

将涉及的类打成jar,进行测试。

tomcat阅读源码中涉及的知识点---自定义类加载器

tomcat阅读源码中涉及的知识点---自定义类加载器

发现app1执行报错,报找不到VersionInfo.getExtend的方法。看输出,是先载入了common.jar 1.0 版本的jar包(现在1.0和1.1的先后顺序,依赖类加载器查找方式,这里例子为先找到了1.0版本的),等到app1要执行的时候,发现Version已经载入进来了,就直接使用。

tomcat阅读源码中涉及的知识点---自定义类加载器

下面,研究如果通过自定义类加载器,避免这种情况的发生。

首先查看ClassLoad.java 的部分源码:可以看到,loadClass使用了递归, 如果当前类加载器未加载过这个class,就从父加载器查找。如果父加载器也找不到,则从当前加载器查找。

tomcat阅读源码中涉及的知识点---自定义类加载器


如果子定义的类加载器还是继承双亲委派模型,那么把jar放在启动脚本的classPath,那么不同类加载器最终得到的还是同一个class。

把com.common 打成jar,在classPath中指定。

tomcat阅读源码中涉及的知识点---自定义类加载器


通过反射调用jar包,输入的内容是类加的,说明是同一个class。

tomcat阅读源码中涉及的知识点---自定义类加载器tomcat阅读源码中涉及的知识点---自定义类加载器


在classPath中不指定com.common 的jar包,执行结果是单独的,每个方法不累加,说明是两个类加载器中是不同的jar包。

tomcat阅读源码中涉及的知识点---自定义类加载器


这里举的例子比较简单,也不是非常具有代表性。但是可以看到,由不同类加载器加载的class,是没有相关性的。

但是,我们实际应用开发中,不可能都通过反射(运行态)来进行方法的调用(实际:入口方法由反射调用,并设置线程的上下文classLoader, 使得后面所有的classLoader都通过上下文设置的classLoader来进行类的载入)。如果在classPath路径中,部分指定的jar包可以不用继承双亲委派模型,优先由自定义的类加载器进行加载class,那么不同应用间相同的class就不会相互干扰了.

后续重点分析tomcat中, WebappClassLoaderBase.java (webapp的类加载器)的代码。