您的位置:首页 > 编程语言 > Java开发

好记性不如烂笔头81-spring3.x学习(2)-java类加载器ClassLoader

2015-03-17 17:33 155 查看

java类加载器ClassLoader的简单说明

ClassLoader是J***A用来处理类加载的类,它管理着具体类的运行时上下文。

ClassLoader先是bootstrap classloader,然后是extension classloader,最后才是system classloader。越是重要的越在靠前面。这样做的原因是出于安全性的考虑,试想如果有不怀好意者修改了一个基础包,比如 “java.lang.System”类。值得庆幸的是,目前JVM这种委托机制保证了用户即使具有一个这样的类, 也把它加入到了类路径中,但是它永远不会被载入,因为这个类总是由bootstrap classloader来加载的。

如果我们执行下: System.out.println(System.class.getClassLoader());

将会看到结果是null,这就表明java.lang.System是由bootstrap classloader加载的,因为bootstrap classloader不是一个真正的ClassLoader实例,而是由JVM实现的。

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

我们总能通过静态方法ClassLoader.getSystemClassLoader()找 到该类加载器。如果没有特别指定,则用户自定义的任何类加载器都将该类加载器作为它的父加载器。执行以下代码即可获得:

System.out.println(System.getProperty(“java.class.path”));

输出结果则为用户在系统属性里面设置的CLASSPATH。

classloader 加载类的全盘负责委托机制

classloader 加载类用的是全盘负责委托机制。所谓全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有 Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入;委托机制则是先让parent(父)类加载器 (而不是super,它与parent classloader类不是继承关系)寻找,只有在parent找不到的时候才从自己的类路径中去寻找。此外类加载还采用了cache机制,也就是如果 cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么我们修改了Class但是 须重新启动JVM才能生效的原因。

类装载器ClassLoader把一个类装入JVM的步骤

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

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

3.请求parent classloader载入,如果成功到8,不成功到5

4.请求jvm从bootstrap classloader中载入,如果成功到8

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

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

7.抛出ClassNotFoundException.

8.返回Class.

java类加载器ClassLoader的简单源代码示例

[code]package com.spring;
import java.net.URL;

/**  
 * 简单的J***A类装载器 ClassLoader
 * 网上很流行的获取classloader加载的核心类库的方法是错误的,这里特意说明下
 *  
 * @author 范芳铭
 */ 
public class EasyClassLoaderTest {
    public static void main(String[] args){
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        System.out.println("当前的 loader:" + loader);
        System.out.println("父 loader:  " + loader.getParent());
        System.out.println("祖父级 loader:" + loader.getParent().getParent());

        System.out.println("--bootstrap classloader加载的核心类库 ");
        URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
           for (int i = 0; i < urls.length; i++) {
             System.out.println(urls[i].toExternalForm());
        }
    }
}


经典的java.lang.NoSuchMethodError 错误

java.lang.NoSuchMethodError ,第一次发现这个错误,大概是10年前用Jbuilder开发EJB系统的时候;当时部门的同事就和玩魔术一样,把一些jar包的加载顺序做了一些调整,然后系统就莫名其妙的好用了。

那个膜拜,那个崇敬,那个稀里糊涂……

这个错误归根到底,还是由于JVM的 classloader 加载类用的是全盘负责委托机制引起的。我们在类路径下放了多个不同版本的包,比如commons-lang 1.x.jar 和commons-lang 2.x.jar。 我们刚好用到了commons-lang 2.x.jar的某个方法,但是这个方法在commons-lang 1.x.jar中不存在。而JVM的加载器碰巧从commons-lang 2.x.jar中加载类,于是java.lang.NoSuchMethodError错误就发生了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: