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

java类加载器ClassLoader的简单说明

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

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的简单源代码示例

package com.spring;

import java.net.URL;

/** * 简单的JAVA类装载器 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错误就发生了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值