技术开发 频道

WebSphere应用服务器类加载机制实践

【IT168 专稿】    本文将会从Java平台本身的类加载机制谈起,然后向读者展现WebSphere Application Server(WAS)中如何应用扩展Java本身的类加载机制。本文还将给出一些常见的由类加载的造成的问题,分析背后的原因,并给出相应的解决方案。

    关键字:

    JVM — Java Virtual Machine,Java虚拟机,是运行Java程序的平台,不同的操作系统有不同的实现。

    classloader — 类加载器,是JVM的一个重要组件,完成加载Java Class文件进JVM。

    Class — Java类型定义文件,定义的数据与相应操作方法,可被classloader加载到JVM上根据它产生相应的运行实例,并可以调用相应的方法。

    让我们从最基本的说起 — Java平台的类加载机制

    首先大家要知道为什么要有classloader,它是做什么的?

    Java是一门语言,但它更一个平台,因为它提供了一个运行平台JVM(虚拟机),隔离了将要运行的程序与当前所在的操作系统。

    而在Java这个平台要运行什么本身是动态未知的,我们写的Java程序都是在需要的时候被动态的加载上去的。Java本身提供了一套类加载机器。总的来说,所有装在Java虚拟机上运行的类都是由classloader这个东西来完成的。

    那classloader是如何工作的?

    首先要强调一点,所有的Java类都是由classloader动态的加载到Java虚拟机上然后再动行的。这里的动态主要表现方式是三种,见表1。

表1 Java的动态加载特性

    当JVM(Java虚拟机)默认启动时,会形成由三个类加载器组成的初始类加载器层次结构:

    bootstrap classloader

    |

    extension classloader

    |

    system classloader

    bootstrap classloader — 引导(也称为原始)类加载器,它负责加载Java的核心类。

    extension classloader — 扩展类加载器,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中JAR的类包。

    system classloader — 系统(也称为应用)类加载器,它负责在JVM被启动时,加载来自在命令java中的-classpath或者java.class.path系统属性或者CLASSPATH操作系统属性所指定的JAR类包和类路径。

    如上所示,classloader是有父子结构的,如system classloader的父亲是extension classloader,extension classloader的父亲bootstrap classloader,bootstrap classloader没有父亲,它是JVM一启动就存在的。

    我们还可以扩展已有的Classloader类,通过覆盖ClassLoader的findClass方法来实现自己的载入策略,甚至覆盖loadClass方法来实现自己的载入过程,这样来满足加载特定类的需求(比如只加载名字前缀是ABC的类)。这样它就成了system classloader下面的第四层。当然,因为这个我们扩展的classloader本身也是一个Java类,它也是被前面的某个classloader加载进来的.

    在默认的JVM设计中,classloader加载Class的过程大致如下:

    1.检测此Class是否载入过(即在JVM中是否有此Class),如果有到第8,如果没有到第2。

    2.如果父亲classloader不存在(没有父亲,那一定是bootstrap classloader了),到第4。

    3.请求父亲classloader载入,如果成功到第8,不成功到第5。

    4.请求JVM让bootstrap classloader去加载,如果成功到第8。

    5.寻找Class文件(从与此classloader相关的类路径中寻找)。如果找不到则到第7。

    6.从文件中载入Class,到第8。

    7.抛出ClassNotFoundException。

    8.返回Class。

    我们可以看到,classloader加载Class的顺序是先委托其parent来加载,直到所有的parent都不能加载才自己去加载。

    Java使用classloader原因,除了可以达到动态性之外,其实最重要的原因还有安全性,体现在下面两点:

    1.核心的类不可能被仿照(这主要是因为先parent委托机制的作用),比如我们不可能加载一个自己写的放在classpath下的java.lang.String类,因为Java总是parent优先,在系统目录下面的String类总是被优先加载。

    2.我们可以指定,控制到特定的载入点,不会误用,比如我只要加载目录的ABC下面的类。

    Java中每个类别都是与加载其进虚拟机的classloader相关联起来的,在同一个运行时的虚拟机中,同一个类型可以被不同的classloader载入多次。

0
相关文章