Tomcat类加载机制

tomcat组成 在这里插入图片描述

tomcat主要由以上组建组成.
整个的http请求是通过tomcat以上组件协调完成的,server和service完成请求的基本设施,connector通过指定的协议和端口监听用户的请求,通过一层一层的处理,最终封装好响应信息返回给客户端.


tomcat类加载

下图简述tomcat类加载过程:
在这里插入图片描述

tomcat的启动方式都是通过在org.apache.catalina.startup.BootStrap类中的main方法中启动完成的.
首先会加载JVM运行所需的类,以及一些扩展类,然后加载tomcat系统运行所需的类,然后就是开始加载webapp应用对应的class文件以及lib.tomcat在启动的过程中回去解析对应配置文件的server.xml以及各web应用的web.xml,首先就会解析的,解析成键值对.。
web应用在启动的时候,都会创建一个上下文serveletContext,把解析成键值对以后,封装到上下文之中。


Tomcat 如何实现自己独特的类加载机制?

所以,Tomcat 是怎么实现的呢?牛逼的Tomcat团队已经设计好了。我们看看他们的设计图:
在这里插入图片描述

我们看到,前面3个类加载和默认的一致,CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebappClassLoader则是Tomcat自己定义的类加载器,它们分别加载/common/、/server/、/shared/*(在tomcat 6之后已经合并到根目录下的lib目录下)和/WebApp/WEB-INF/*中的Java类库。其中WebApp类加载器和Jsp类加载器通常会存在多个实例,每一个Web应用程序对应一个WebApp类加载器,每一个JSP文件对应一个Jsp类加载器。

commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;

从启动类BootStrap中的源码也可以看出来:

private void initClassLoaders() {
        try {
            commonLoader = createClassLoader("common", null);
            if( commonLoader == null ) {
                // no config file, default to this loader - we might be in a 'single' env.
                commonLoader=this.getClass().getClassLoader();
            }
            catalinaLoader = createClassLoader("server", commonLoader);
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            handleThrowable(t);
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }

从图中的委派关系中可以看出:

CommonClassLoader能加载的类都可以被Catalina ClassLoader和SharedClassLoader使用,从而实现了公有类库的共用,而CatalinaClassLoader和Shared ClassLoader自己能加载的类则与对方相互隔离。

WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。

而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能。

好了,至此,我们已经知道了tomcat为什么要这么设计,以及是如何设计的,那么,tomcat 违背了java 推荐的双亲委派模型了吗?答案是:违背了。 我们前面说过:

双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当由自己的父类加载器加载。

很显然,tomcat 不是这样实现,tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器。

我们扩展出一个问题:如果tomcat 的 Common ClassLoader 想加载 WebApp ClassLoader 中的类,该怎么办?
看了前面的关于破坏双亲委派模型的内容,我们心里有数了,我们可以使用线程上下文类加载器实现,使用线程上下文加载器,可以让父类加载器请求子类加载器去完成类加载的动作。牛逼吧。


WebAppClassLoader源码分析

下图是一个概况的流程图, 简介起见,绘图过程中移除了缓存功能.
在这里插入图片描述
下面是关键的代码,已经添加了注释.

//WebappClassLoader.loadClass (Tomcat 7.0)  
    @Override  
    public synchronized Class<?> loadClass(String name, boolean resolve)  
        throws ClassNotFoundException {  
  
        if (log.isDebugEnabled())  
            log.debug("loadClass(" + name + ", " + resolve + ")");  
        Class<?> clazz = null;  
  
        //检查当前ClassLoad是否已经停止了  
        // Log access to stopped classloader  
        if (!started) {  
            try {  
                throw new IllegalStateException();  
          
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值