Tomcat的类加载器

一.Jvm的类加载器

img点击并拖拽以移动编辑

  1. Bootstrap:用于加载JVM提供的基础运行类,即位于%JAVA_HOME%/jre/lib目录下的核心类库。
  2. Extension: Java提供的一个标准的扩展机制用于加载除核心类库外的Jar包, 即只要复制到指定的扩展目录(可以多个)下的Jar,JVM会自动加载(不需要通过-classpath指定)。默认的扩展目录是%JAVA_HOME%/jre/lib/ext。典型的应用场景就是,Java使用该类加载器加载JVM默认提供的但是不属于核心类库的Jar,如JCE R等。不推荐将应用程序依赖的类库放置到扩展目录下,因为该目录下的类库对所有基于该JVM运行的应用程序可见。
  3. System(AppClassLoader):用于加载环境变量CLASSPATH(不推荐使用)指定目录下的或者-classpath运行参数指定的Jar包。System类加载器通常用于加载应用程序Jar包及其启动人口类(Tomcat的Bootstrap类即由System类加载器加载)。

二.Tomcat的类加载器

官方文档

img点击并拖拽以移动编辑

  1. Common:以System为父类加载器,是位于Tomcat应用服务器顶层的公用类加载器。其路径为common.loader,默认指向$CATALINA_HOME/lib下的包。
  2. Catalina: 以Common为父加载器,是用于加载Tomcat应用服务器的类加载器,其路径为server.loader,默认为空。此时Tomcat使用Common类加载器加载应用服务器。
  3. Shared:以Common为父加载器,是所有Web应用的父加载器其路径为shared.loader ,默认为空。此时Tomcat使用Common类加载器作为Web应用的父加载器。
  4. Web应用:以Shared为父加载器,加载/WEB-INF/classes目录下的未压缩的Class和资源文件以及/WEB-INF/lib目录下的Jar包。如前所述,该类加载器只对当前Web应用可见,对其他Web应用均不可见。

从Web应用程序的角度来看,类或资源的加载按以下顺序查找以下存储库

  • Bootstrap classes of your JVM
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application
  • System class loader classes (described above)
  • Common class loader classes (described above)

三.Tomcat类加载器这样设计的优点

应用服务器通常会自行创建类加载器以实现更灵活的控制,这一方面是对规范的实现(Servlet规范要求每个Web应用都有一个独立的类加载器实例),另一方面也有架构层面的考虑。

  1. 隔离性: Web应用类库相互隔离,避免依赖库或者应用包相互影响。设想一下,如果我们有两个Web应用,一个采用了Spring2.5,一个采用了Spring 4.0,而应用服务器使用一个类加载器加载,那么Web应用将会由于Jar包覆盖而导致无法启动成功。
  2. 灵活性:既然Web应用之间的类加载器相互独立,那么我们就能只针对一个Web应用进行重新部署,此时该Web应用的类加载器将会重新创建,而且不会影响其他Web应用。如果采用一个类加载器,显然无法实现,因为只有一个类加载器的时候,类之间的依赖是杂乱无章的,无法完整地移除某个Web应用的类。
  3. 性能:由于每个Web应用都有一个类加载器,因此Web应用在加载类时,不会搜索其他 Web应用包含的Jar包,性能自然高于应用服务器只有一个类加载器的情况。

四.Tomcat类加载器的实现

Bootstrap:initClassLoaders();

  1. commonLoader = createClassLoader("common", null);
  2. catalinaLoader = createClassLoader("server", commonLoader);
  3. sharedLoader = createClassLoader("shared", commonLoader);

digester的创建:

  1. Catalina:createStartDigester();
  2. Digester digester = new Digester();

创建类的过程:

  1. ObjectCreateRule:begin();
    1. Class<?> clazz = digester.getClassLoader().loadClass(realClassName);
  2. SetNextRule:end();
    1. IntrospectionUtils.callMethod1(parent, methodName,child, paramType, digester.getClassLoader());
    2. digester.getClassLoader();
    3. Thread.currentThread().getContextClassLoader();
posted @ 2022-08-24 11:35  菜阿  阅读(125)  评论(0编辑  收藏  举报