Java中的类加载器以及Tomcat的类加载机制

时间:2022-03-24 23:01:44

在加载阶段,虚拟机需要完成以下三件事情:

1、通过一个类的全限定名来获取其定义的二进制字节流。

2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

3、在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。

类加载器(class loader)是 Java中的一个很重要的概念。Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。

1、JVM中的类加载器

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的,基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例。系统提供的类加载器主要有下面三个:

  • 引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自java.lang.ClassLoader。它负责加载存放在JDK\jre\lib(JDK代表JDK的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库。它载入的核心类包括java.lang包和java.io包等
  • 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。扩展目录依赖于jdk供应商的具体实现,sun公司默认的标准扩展目录是/jdk/jre/lib/ext。
  • 系统类加载器(system class loader):它根据 Java 应用的类路径(环境变量CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

Java中的类加载器以及Tomcat的类加载机制

上图来自xingoo博客,说明了JVM中类加载的顺序(双亲委派模型):

  • 用户自己的类加载器,把加载请求传给父加载器,父加载器再传给其父加载器,一直到加载器树的顶层。
  • 最顶层的类加载器首先针对其特定的位置加载,如果加载不到就转交给子类。
  • 如果一直到底层的类加载都没有加载到,那么就会抛出异常ClassNotFoundException。

之所以要把底层的加载器委托给父加载器处理,是为了保证java核心库的类型安全,所有 Java 应用都至少需要引用java.lang.Object类,也就是说在运行的时候,java.lang.Object这个类需要被加载到 Java 虚拟机中。如果这个加载过程由 Java 应用自己的类加载器来完成的话,很可能就存在多个版本的 java.lang.Object类,而且这些类之间是不兼容的。通过代理模式,对于 Java 核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类,是互相兼容的。

2、WEB容器中的类加载器

对于运行在 Java EE容器中的 Web 应用来说,类加载器的实现方式与一般的 Java 应用有所不同。不同的 Web 容器的实现方式也会有所不同。以 Apache Tomcat 来说,每个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式,所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的。

这是 Java Servlet 规范中的推荐做法,其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。这种代理模式的一个例外是:Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。

Java中的类加载器以及Tomcat的类加载机制

上图说明了tomcat类加载器的流程,这里只记录一下结论,详细分析请参考xinggo的博客

  • 使用bootstrap引导类加载器加载(加载JVM启动所需的类,以及标准扩展类(位于jre/lib/ext下))
  • 使用system系统类加载器加载(加载tomcat启动的类,比如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下。)
  • 使用应用类加载器在WEB-INF/classes中加载
  • 使用应用类加载器在WEB-INF/lib中加载
  • 使用common类加载器在CATALINA_HOME/lib中加载

参考:

http://www.ibm.com/developerworks/cn/java/j-lo-classloader/

http://www.cnblogs.com/xing901022/p/4574961.html

http://www.flyne.org/article/252