Tomcat类加载机制以及线程上下文类加载器

Tomcat类加载机制以及线程上下文类加载器

  

tomcat类加载需要解决的问题

tomcat是一个很经典的web服务器,一个服务器就相当于一个Java应用,而在这个Java应用中又有着多个被部署的Web应用,因此,有着如下的几个问题等着被解决:

1、多个web应用之间不能相互影响;

2、jsp能够热部署;

3、web服务器本身使用的类库,不被干扰;

4、多个web应用能够共享lib;

我们先来回顾一下传统的类加载机制的流程图:

双亲委托机制

在双亲委托机制中,启动类加载器为Java启动时需要加载的类,拓展类加载器为jre中一个叫ext文件夹底下的类,应用加载器则是加载classpath底下的类,可以通过System.getProperty("java.class.path");获得,用以加载应用编译产生的类。

双亲委托是为了保证类在内存中的唯一性,防止如恶意Object类出现的类似情况,而产生的一种机制。双亲委托机制会让类加载器先去找parent加载器,若parent等于null,则会去找启动类加载器(由于启动类加载器是由c++编写的,所以Java应用无法获取其引用),若父类加载器无法加载类,才会自己去加载类。

tomcat的类加载结构以及解决方案

简单粗暴,直接上图,以下为tomcat类加载的结构:

tomcat类加载结构图

可以看出,上半部分的类加载还是和普通的JVM一模一样的,而在应用类加载器底下,就有了一层,common类加载器,用于加载/common底下的类,此为tomcat的基础类加载器;而往下有一个分叉,Catalina类加载器用于加载tomcat的私有的类(/catalina),对其他web应用不可见;另外一个分叉,有shared类加载器,顾名思义,是用于存放各个web应用共享的类加载器(/catalina);而WebApp类加载器则是每一个Web应用独有的,用于隔离不同web应用之间的影响;jsp类加载器则是每一个jsp独有的类加载器,每当jsp修改时,都会丢弃原有的jsp类加载器,新建一个jsp类加载器,以完成hotswap。

common,shared,Catalina,这三个类加载器都是tomcat单独的类加载器实例,在tomcat6以后,若没有去配置一个叫catalina的配置文件,去修改其中的catalina和shared类加载器路径,则不会开启shared类加载器和catalina类加载器,只会用common类加载器去加载/lib路径底下的类。

好了,由上我们已经解决了四个web服务器问题中的三个:

1、独立的web类加载器可以隔离每个web应用的类加载;

2、jsp类加载器的修改即卸载可以实现hotswap;

3、catalina类加载器可以实现tomcat私有类加载,对web应用不可见;

那么只剩最后一个问题,类的共享,试问,如果十个web应用都引入了spring的类,由于web类加载器的隔离,那么对内存的开销是很大的。此时我们可以想到shared类加载器,我们肯定都会选择将spring的jar放于shared目录底下,但是此时又会存在一个问题,shared类加载器是webapp类加载器的parent,若spring中的getBean方法需要加载web应用底下的类,这种过程是违反双亲委托机制的。

打破双亲委托机制的桎梏:线程上下文类加载器

线程上下文类加载器是指的当前线程所用的类加载器,可以通过Thread.currentThread().getContextClassLoader()获得或者设置。

在spring中,他会选择线程上下文类加载器去加载web应用底下的类,如此就打破了双亲委托机制了。

猜你喜欢

转载自blog.csdn.net/that_is_cool/article/details/81225810