`

java与tomcat类加载机制

    博客分类:
  • java
阅读更多

前言:

类加载机制,听起来“高大上”的东西,其实不是很难。理解类加载机制,对我们日常的开发和对tomcat的理解会有一个提升。

一  java的类加载机制。

    1, java中类加载器的种类以及作用。

         (1)bootstrap            启动类加载器  JVM实现的一部分,在JVM运行的时候就加载 JAVA的核心API(java.lang.* or java.io.*)

         (2)ExtClassLoder     扩展类加载器  用来加载 java扩展的API 也就<JRE>/lib/ext 下面的类

         (3)AppClassLoder   系统类加载器  加载CLASSPATH下面的类,也就是用户自己写的类

 

    2, java类加载器的层次关系 和 调用顺序

          加载顺序 :按照从上到下的顺序 加载 类

          bootstrap 类加载器是由C++代码实现的 位于顶层

          ExtClassLoder 类加载器 位于中层

          AppClassLoder 类加载器 位于底层   

          注意:(ExtClassLoder 是 AppClassLoder 的父类 两者由java代码实现)

 

   3, java类加载器的双亲委托模型

       

 

        当一个类加载请求加载某个类的时候,首先检查是否已经加载过这个类,如果加载过直接返回。如果没有加载过,首先会委托父类加载器,父类加载器也会检查时候加载过这个类,如果还是没有则继续向上委托

        如果最后的父类加载器不能加载这个类。则调用 bootstrap 去加载这个类,如果还是找不到则会抛出ClassNotFoundException。

        这种模型的用途就是为了解决 类载入过程中的安全性问题。如果有恶意用户自定义了 一个类 如Object 类 去覆盖 java 关键类 则会有产生安全性问题。

    4,加载器的命名空间 

        每个加载器都有自己的命名空间,命名空间由该加载器以及父类所有的加载器所加载的类组成,当加载器加载一个雷的时候

首先会去自己的命名空间中查找 是否 加载过这个类。

        在同一命名空间不会出现出现类的完整名字完全相同的两个类,在不同的命名空间中有可能出现类的完整名字完全相同的两个类。

类加载器 命名空间
Loader1 Class1
Loader2 Class1Class2
Loader3 Class1Class2Class3
Loader4 Class1Class2Class3

 

5, 运行时包

      由同一类加载器加载属于相同包的类,组成了运行时包。

      决定两个类是否属于同一运行时包,不仅要看包名是否相同,还要看是否由,同一个ClassLoader加载。只有属于同一运行时包的类,才能互相访问包可见的类和成员。

      这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自己定义了一个类 java.lang.xxx ,并用自定义的 ClassLoader 装载,由于 Java.lang.* 和 java.lang.xxx 是由不同的装载器装载,属于不同的运行时包,所以 java.lang.xxx 不能访问核心类库 java.lang 中类的包可见成员。

 

二  Tomcat 类加载机制。

先上一张tomcat 5的类 tomcat类加载器的结构图,虽然东西老,但是原理相同。

          Bootstrap
                  |
              System
                  |
            Common
          /                \
 Catalina          Shared
                      /  ... ...    \
            webapp1        webappN 

(1)Bootstrap:该加载器包含由JVM提供的基本的运行时类,加上放置在系统扩展目录(<JAVA_HOME/jre/lib/ext>)的JAR文件中的类。

注意——有些Java虚拟器(JVMs)也许把它作为不止一个类装载器用,或者作为一个类装载器用。

(2)System - 这个类装载器通常是以CLASSPATH环境变量的内容为基础来初始化的。在使用Tomcat作为Servlet/JSP容器的Web环境中,Tomcat在启动过程中清除了原有CLASSPATH的内容,并对其进行了重新定义。

  • $CATALINA_HOME/bin/bootstrap.jar - 包含用来初始化Tomcat 5服务器的main()方法,以及它所依赖的类装载器执行类。 

  • $JAVA_HOME/lib/tools.jar - 包含用来把JSP页面转换成servlet类的"javac"编译器。  

  • $CATALINA_HOME/bin/commons-logging-api.jar - Jakarta commons 记录应用程序界面。

  • $CATALINA_HOME/bin/commons-daemon.jar - Jakarta commons        daemon API.

  • jmx.jar - JMX 1.2 执行。

(3)Common:该类加载器包含一些对Tomcat内部类和web应用可见的额外类。其中包括1jasper-compiler.jar:JSP 2.0编译器(2)jsp-api.jar:JSP 2.0 API(3)servlet-api.jar:servlet 2.4 API等等。

(4)Catalina:该加载器初始化用来包含实现Tomcat 5本身所需要所有类和资源;

(5)Shared:在所有的web应用程序间共享的类和资源;

(6)WebappN:为每个部署在单个Tomcat 5实例上的Web应用创建的类加载器。加载/WEB-INF/classes和WEB-INF/lib下的类和资源

 

tomcat 的类加载机制与java的类加载委派模型不同之处就是,当WebappN被请求记载一个类的时候,并不一定完全会按照 java类加载器的委托模式,WebappN首先会在本地库中查找而不是直接委托。但是也有例外

作为 JRE 一些基本类的一部分类不能被覆盖

下面附上tomcat WebappClassLoader 的load方法

    public synchronized Class loadClass(String name, boolean resolve)  
            throws ClassNotFoundException {  
      
            Class clazz = null;  
      
            //首先检查已加载的类  
            // (0) Check our previously loaded local class cache  
            clazz = findLoadedClass0(name);  
            if (clazz != null) {  
                if (log.isDebugEnabled())  
                    log.debug("  Returning class from cache");  
                if (resolve)  
                    resolveClass(clazz);  
                return (clazz);  
            }  
      
            // (0.1) Check our previously loaded class cache  
            clazz = findLoadedClass(name);  
            if (clazz != null) {  
                if (log.isDebugEnabled())  
                    log.debug("  Returning class from cache");  
                if (resolve)  
                    resolveClass(clazz);  
                return (clazz);  
            }  
      
            // (0.2) Try loading the class with the system class loader, to prevent  
            //       the webapp from overriding J2SE classes  
            try {  
                clazz = system.loadClass(name);  
                if (clazz != null) {  
                    if (resolve)  
                        resolveClass(clazz);  
                    return (clazz);  
                }  
            } catch (ClassNotFoundException e) {  
                // Ignore  
            }  
      
            // (0.5) Permission to access this class when using a SecurityManager  
            if (securityManager != null) {  
                int i = name.lastIndexOf('.');  
                if (i >= 0) {  
                    try {  
                        securityManager.checkPackageAccess(name.substring(0,i));  
                    } catch (SecurityException se) {  
                        String error = "Security Violation, attempt to use " +  
                            "Restricted Class: " + name;  
                        log.info(error, se);  
                        throw new ClassNotFoundException(error, se);  
                    }  
                }  
            }  
      
            boolean delegateLoad = delegate || filter(name);  
            //Tomcat允许按照配置来确定优先使用本Web应用的类加载器加载还是使用父类  
    //加载器来进行类加载,此处先使用父类加载器进行加载  
            // (1) Delegate to our parent if requested  
            if (delegateLoad) {  
                if (log.isDebugEnabled())  
                    log.debug("  Delegating to parent classloader1 " + parent);  
                ClassLoader loader = parent;  
                if (loader == null)  
                    loader = system;  
                try {  
                    clazz = loader.loadClass(name);  
                    if (clazz != null) {  
                        if (log.isDebugEnabled())  
                            log.debug("  Loading class from parent");  
                        if (resolve)  
                            resolveClass(clazz);  
                        return (clazz);  
                    }  
                } catch (ClassNotFoundException e) {  
                    ;  
                }  
            }  
            //使用本地的类加载器进行加载  
            // (2) Search local repositories  
            if (log.isDebugEnabled())  
                log.debug("  Searching local repositories");  
            try {  
                clazz = findClass(name);  
                if (clazz != null) {  
                    if (log.isDebugEnabled())  
                        log.debug("  Loading class from local repository");  
                    if (resolve)  
                        resolveClass(clazz);  
                    return (clazz);  
                }  
            } catch (ClassNotFoundException e) {  
                ;  
            }  
            //如果没有特殊配置的话,使用父类加载器加载类  
            // (3) Delegate to parent unconditionally  
            if (!delegateLoad) {  
                if (log.isDebugEnabled())  
                    log.debug("  Delegating to parent classloader at end: " + parent);  
                ClassLoader loader = parent;  
                if (loader == null)  
                    loader = system;  
                try {  
                    clazz = loader.loadClass(name);  
                    if (clazz != null) {  
                        if (log.isDebugEnabled())  
                            log.debug("  Loading class from parent");  
                        if (resolve)  
                            resolveClass(clazz);  
                        return (clazz);  
                    }  
                } catch (ClassNotFoundException e) {  
                    ;  
                }  
            }  
            //若最终类还是没有找到,抛出异常  
            throw new ClassNotFoundException(name);  
      
        }  

 

 从一个网络程序的角度来看,类和资源的装载以这样的顺序在下列贮藏室进行查找:

  • 你的JVM的Bootstrap类
  • 系统类装载器类(描述如上)
  • 你的网络程序的/WEB-INF/classes
  • 你的网络程序的/WEB-INF/lib/*.jar
  • $CATALINA_HOME/common/classes
  • $CATALINA_HOME/common/endorsed/*.jar
  • $CATALINA_HOME/common/lib/*.jar
  • $CATALINA_BASE/shared/classes
  • $CATALINA_BASE/shared/lib/*.jar
  • 大小: 88.1 KB
分享到:
评论

相关推荐

    JAVA-JVM-01类加载机制

    java中JVM类加载器和双亲委派机制剖析,类加载示例、加载器示例、自定义一个类加载器示例;Tomcat自定义加载器详解

    tomcat使用与调优,nginx

    第五部分:Tomcat 类加载机制剖析 第六部分:Tomcat 对 Https 的⽀持及 Tomcat 性能优化策略 nginx 第⼀部分:Nginx基础回顾(Nginx是什么?能做什么事情(应⽤在什么场合)?常⽤命令是什么?) 第⼆部分:Nginx核⼼...

    Tomcat 类加载器的实现方法及实例代码

    1. Java 类加载机制 类加载就是把编译生成的 class 文件,加载到 JVM 内存中(永久代/元空间)。 类加载器之所以能实现类隔离,是因为两个类相等的前提是它们由同一个类加载器加载,否则必定不相等。 JVM 在加载时,...

    关于tomcat的一些自己介绍

    1. TOMCAT的组件介绍及处理请求的流程 2. tomcat管理 3. 提一下tomcat安全和java安全机制 4. java的类加载机制 5. tomcat的类加载机制 6. tomcat搭建集群环境

    JAVA上百实例源码以及开源项目源代码

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA上百实例源码以及开源项目

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java开源包4

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    java开源包101

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    java开源包11

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    java8集合源码分析-java-agent:基于java5Instrumentapi实现的mock框架

    java8 集合源码分析 1 介绍 1.1 用途 单元测试mock 联调、集成测试mock 支持mock静态方法,final方法,私有...理解java类加载机制、tomcat类加载机制 学习groovy语言 学习使用javassist增强字节码 了解dubbo消费端执

    java开源包6

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    java开源包9

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    java开源包8

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    java开源包5

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    java开源包10

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    Tomcat.ClassLoader.rar_Java编程_Java_

    详细讲解java classloader知识和tomcat中的类加载机制

    java开源包1

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    java开源包3

    Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java类 Java批量作业执行框架 MyBatchFramework MyBatchFramework 是一个开源的轻量级的用以创建...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    / 170 第7章 虚拟机类加载机制 / 171 7.1 概述 / 171 7.2 类加载的时机 / 172 7.3 类加载的过程 / 176 7.3.1 加载 / 176 7.3.2 验证 / 178 7.3.3 准备 / 181 7.3.4 解析 / 182 7.3.5 初始化 / 186 7.4 类...

    【白雪红叶】JAVA学习技术栈梳理思维导图.xmind

    类加载机制 双亲委派 OSGI 算法 搜索 二分 排序 选择 冒泡 插入 快速 归并 堆 桶 基数 常用算法 贪婪 回溯 剪枝 动态规划 数据挖掘算法 KMP算法 GZZ算法 HASH分桶 关联规则算法 APRORIVE...

Global site tag (gtag.js) - Google Analytics