一. tomcat是如何打破双亲委派机制的?
@H_404_2@首先,来举个例子,通常,一个tomcat要加载几个应用程序呢? 当然是n多个应用程序,加入我们使用的都是spring的框架,那我们能保证所有的应用程序都是用spring4 或者spring5 么? 不可能,他可能既有spring4的项目,又有spring5的项目. 那么tomcat在加载spring4项目的war包是,会不会和spring5项目的war包冲突呢? 因为spring4,和 spring5中有很多类的类名是一样的,但是实现不一样. 如果都是交给父类加载器加载,那么肯定只能加载一份. 也就是spring4和spring5的项目不能共存. 而实际上的情况呢? 我们的tomcat可以加在各种各样类型的war包,相互之间没有影响. 他是怎么做到的呢? @H_404_2@因为tomcat打破了双亲委派机制,下面我们就来看看tomcat是如何打破双亲委派机制的? @H_404_2@1. tomcat第一部分自定义类加载器(黄色部分)
@H_404_2@这部分类加载器,在tomcat7及以前是tomcat自定义的三个类加载器,分别在家不同文件加载的jar包. 而到了tomcat8及以后,tomcat将这三个文件夹合并了,合并成了一个lib包. 也就是我们现在看到的lib包 @H_404_2@- commonClassLoader: tomcat最基本的类加载器,加载路径中的class可以被tomcat容器本身和各个webapp访问;
- catalinaClassLoader: tomcat容器中私有的类加载器,加载路径中的class对于webapp不可见
- sharedClassLoader: 各个webapps共享的类加载器,加载路径中的class对于所有的webapp都可见,但是对于tomcat容器不可见.
二. 自定义tomcat的war包类加载器
@H_404_2@如何打破双亲委派机制,我们已经写过一个demo了. 详见: https://www.cnblogs.com/ITPower/p/13211490.html @H_404_2@那么,现在我有两个war包,分处于不同的文件夹,tomcat如何使用各自的类加载器加载自己包下的class类呢? @H_404_2@我们来举个例子,比如: 在我的home目录下有两个文件夹,tomcat-test和tomcat-test1. 用这两个文件夹来模拟两个项目. @H_404_2@@H_403_64@
@H_404_2@ @H_404_2@ 在他们的下面都有一个com/lxl/jvm/User1.class @H_404_2@public static void main(String[] args) throws Exception {
// 第一个类加载器 DefinedClassLoaderTest classLoader = new DefinedClassLoaderTest("/Users/luoxiaoli/tomcat-test"); Class<?> clazz = classLoader.loadClass("com.lxl.jvm.User1"); Object obj = clazz.newInstance(); Method sout = clazz.getDeclaredMethod(sout",null); sout.invoke(obj,); System.out.println(clazz.getClassLoader().getClass().getName()); // 第二个类加载器 DefinedClassLoaderTest classLoader1 = new DefinedClassLoaderTest("/Users/luoxiaoli/tomcat-test1); Class<?> clazz1 = classLoader1.loadClass(); Object obj1 = clazz1.newInstance(); Method sout1 = clazz1.getDeclaredMethod(); sout1.invoke(obj1,1)">.println(clazz1.getClassLoader().getClass().getName()); }
调用了user1的sout方法
com.lxl.jvm.DefinedClassLoaderTest
调用了另外一个项目user1的sout方法,他们是不同的
com.lxl.jvm.DefinedClassLoaderTest