tomcat是如何打破双亲委派机制的?

简介: tomcat是如何打破双亲委派机制的?

一. tomcat是如何打破双亲委派机制的?



首先, 来举个例子, 通常,一个tomcat要加载几个应用程序呢? 当然是n多个应用程序, 加入我们使用的都是spring的框架, 那我们能保证所有的应用程序都是用spring4 或者spring5 么? 不可能, 他可能既有spring4的项目, 又有spring5的项目. 那么tomcat在加载spring4项目的war包是, 会不会和spring5项目的war包冲突呢? 因为spring4, 和 spring5中有很多类的类名是一样的, 但是实现不一样. 如果都是交给父类加载器加载, 那么肯定只能加载一份. 也就是spring4和spring5的项目不能共存. 而实际上的情况呢? 我们的tomcat可以加在各种各样类型的war包, 相互之间没有影响. 他是怎么做到的呢?


因为tomcat打破了双亲委派机制, 下面我们就来看看tomcat是如何打破双亲委派机制的?

1187916-20200701044305758-214059128.png

如上图, 上面的橙色部门还是和原来一样, 采用双亲委派机制. 而黄色部分是tomcat第一部分自定义的类加载器, 这部分主要是加载tomcat包中的类, 这一部分依然采用的是双亲委派机制, 而绿色部分是tomcat第二部分自定义类加载器, 正事这一部分, 打破了类的双亲委派机制. 先面我们就来详细看看tomcat自定的类加载器


1. tomcat第一部分自定义类加载器(黄色部分)


这部分类加载器, 在tomcat7及以前是tomcat自定义的三个类加载器, 分别在家不同文件加载的jar包. 而到了tomcat8及以后, tomcat将这三个文件夹合并了, 合并成了一个lib包. 也就是我们现在看到的lib包

1187916-20200701044717389-314223877.png


我们来看看这三个类加载器的主要功能.


  • commonClassLoader: tomcat最基本的类加载器, 加载路径中的class可以被tomcat容器本身和各个webapp访问;
  • catalinaClassLoader: tomcat容器中私有的类加载器, 加载路径中的class对于webapp不可见
  • sharedClassLoader: 各个webapps共享的类加载器, 加载路径中的class对于所有的webapp都可见, 但是对于tomcat容器不可见.


这一部分类加载器, 依然采用的是双亲委派机制, 原因是, 他只有一份. 如果有重复, 那么也是以这一份为准.


2. tomcat第二部分自定义类加载器(绿色部分)


绿色部分是java项目在打war包的时候, tomcat自动生成的类加载器, 也就是说 , 每一个项目打成一个war包, tomcat都会自动生成一个类加载器, 专门用来加载这个war包. 而这个类加载器打破了双亲委派机制. 我们可以想象一下, 加入这个webapp类加载器没有打破双亲委派机制会怎么样?


如果没有打破, 他就会委托父类加载器去加载, 一旦加载到了,  子类加载器就没有机会在加载了. 那么, spring4和spring5的项目想共存, 那是不可能的了.

所以, 这一部分他打破了双亲委派机制


这样一来, webapp类加载器不需要在让上级去加载, 他自己就可以加载对应war里的class文件. 当然了, 其他的项目文件, 还是要委托上级加载的.

 

下面我们来实现一个自定义的类加载器

二. 自定义tomcat的war包类加载器



如何打破双亲委派机制, 我们已经写过一个demo了. 详见: https://www.cnblogs.com/ITPower/p/13211490.html


那么, 现在我有两个war包, 分处于不同的文件夹, tomcat如何使用各自的类加载器加载自己包下的class类呢?


我们来举个例子, 比如: 在我的home目录下有两个文件夹, tomcat-test和tomcat-test1. 用这两个文件夹来模拟两个项目.

1187916-20200701051835458-1643927887.png

1187916-20200701051736312-847437415.png

虽然类名和类路径都是一样的,但是他们的内容是不同的


1187916-20200701052811292-167315798.png

1187916-20200701052750004-1501184878.png

这个时候,如果tomcat要同时加载这两个目录下的User1.class文件, 我们如何操作呢?

其实,非常简单, 按照上面的思路, tomcat只需要为每一个文件夹生成一个新的类加载器就可以了.

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, null);
        System.out.println(clazz.getClassLoader().getClass().getName());
     // 第二个类加载器
        DefinedClassLoaderTest classLoader1 = new DefinedClassLoaderTest("/Users/luoxiaoli/tomcat-test1");
        Class<?> clazz1 = classLoader1.loadClass("com.lxl.jvm.User1");
        Object obj1 = clazz1.newInstance();
        Method sout1 = clazz1.getDeclaredMethod("sout", null);
        sout1.invoke(obj1, null);
        System.out.println(clazz1.getClassLoader().getClass().getName());
    }


他们都是只加载自己目录下的文件.  我们来看看执行结果:


调用了user1的sout方法

com.lxl.jvm.DefinedClassLoaderTest


调用了另外一个项目user1的sout方法, 他们是不同的

com.lxl.jvm.DefinedClassLoaderTest


三. 延伸思考: 我们看到上面tomcat自定义的类加载器中, 还有一个jsp类加载器. jsp是可以实现热部署的, 那么他是如何实现的呢?



我们都知道jsp其实是一个servlet容器, 有tomcat加载. tomcat会为每一个jsp生成一个类加载器. 这样每个类加载器都加载自己的jsp, 不会加载别人的. 当jsp文件内容修改时, tomcat会有一个监听程序来监听jsp的改动. 比如文件夹的修改时间, 一旦时间变了, 就重新加载文件夹中的内容.


具体tomcat是怎么实现的呢? tomcat自定义了一个thread, 用来监听不同文件夹中文件的内容是否修改, 如何监听呢? 就看文件夹的update time有没有变化, 如果有变化了, 那么就会重新加载.

相关文章
|
8月前
|
安全 Java 应用服务中间件
打破Tomcat中的双亲委派机制:探讨与实践
打破Tomcat中的双亲委派机制:探讨与实践
|
安全 Java 应用服务中间件
【JavaWeb】Tomcat底层机制和Servlet运行原理
网络通信:Tomcat使用Java的Socket API来监听特定的端口(通常是8080),接收来自客户端的HTTP请求。 线程池:Tomcat使用线程池来处理并发的请求。当有新的请求到达时,Tomcat会从线程池中获取一个空闲线程来处理该请求,这样可以提高处理效率。 生命周期管理:Tomcat负责管理Servlet和其他Web组件的生命周期,包括初始化、请求处理和销毁等阶段。(init(), run())
|
3月前
|
网络协议 Java 应用服务中间件
深入浅出Tomcat网络通信的高并发处理机制
【10月更文挑战第3天】本文详细解析了Tomcat在处理高并发网络请求时的机制,重点关注了其三种不同的IO模型:NioEndPoint、Nio2EndPoint 和 AprEndPoint。NioEndPoint 采用多路复用模型,通过 Acceptor 接收连接、Poller 监听事件及 Executor 处理请求;Nio2EndPoint 则使用 AIO 异步模型,通过回调函数处理连接和数据就绪事件;AprEndPoint 通过 JNI 调用本地库实现高性能,但已在 Tomcat 10 中弃用
深入浅出Tomcat网络通信的高并发处理机制
|
4月前
|
设计模式 人工智能 安全
【Tomcat源码分析】生命周期机制 Lifecycle
Tomcat内部通过各种组件协同工作,构建了一个复杂的Web服务器架构。其中,`Lifecycle`机制作为核心,管理组件从创建到销毁的整个生命周期。本文详细解析了Lifecycle的工作原理及其方法,如初始化、启动、停止和销毁等关键步骤,并展示了LifecycleBase类如何通过状态机和模板模式实现这一过程。通过深入理解Lifecycle,我们可以更好地掌握组件生命周期管理,提升系统设计能力。欢迎关注【码上遇见你】获取更多信息,或搜索【AI贝塔】体验免费的Chat GPT。希望本章内容对你有所帮助。
|
6月前
|
Java 应用服务中间件 API
开发与运维机制问题之Tomcat要打破双亲委派机制如何解决
开发与运维机制问题之Tomcat要打破双亲委派机制如何解决
56 0
|
8月前
|
Java 应用服务中间件 容器
JavaWeb手写Tomcat底层机制
综上所述,Tomcat作为JavaWeb应用的Servlet容器,在接收请求、解析请求、查找Servlet、创建请求和响应对象、请求分发、生成响应、连接管理等方面起着关键作用。其底层机制通过Socket通信、Servlet生命周期管理、线程池、Session管理等技术实现了整个JavaWeb应用的运行。
49 0
|
8月前
|
缓存 负载均衡 应用服务中间件
【分布式技术专题】「分析Web服务器架构」Tomcat服务器的运行架构和LVS负载均衡的运行机制(修订版)
在本章内容中,我们将深入探讨 Tomcat 服务器的运行架构、LVS 负载均衡的运行机制以及 Cache 缓存机制,并提供相应的解决方案和指导。通过理解这些关键概念和机制,您将能够优化您的系统架构,提高性能和可扩展性。
331 4
【分布式技术专题】「分析Web服务器架构」Tomcat服务器的运行架构和LVS负载均衡的运行机制(修订版)
|
Java 应用服务中间件 Maven
JavaWeb 手写Tomcat底层机制
JavaWeb——手写Tomcat底层 BIO线程模型 + 反射机制。
63 0
|
存储 Java 应用服务中间件
|
Java 应用服务中间件 API
Tomcat 的运行机制
转载地址:  http://wiki.jikexueyuan.com/project/java-web/00-08.html 先不去关技术细节,对一个servlet容器,我觉得它首先要做以下事情:  1:实现Servlet api规范。这是最基础的一个实现,servlet api大部分都是接口规范。如request、response、session、cookie。为了我们应用端
1393 0