Java类加载器详解&双亲委派模式

Java类加载器详解

          新建一个java 对象的时候,JVM 要将这个对象对应的字节码加载到内存中,这个字节码的原始信息存放在classpath( 就是我们新建Java 工程的bin 目录下) 指定的目录下的.class 文件, 类加载需要将.class 文件导入到硬盘中,经过一些处理之后变成字节码在加载到内存中。

一、Java虚拟机种的类加载器

1、类加载器种类

         Java虚拟机中可以安装多个类加载器,系统默认三个主要的类加载器,每个类负责加载特定位置的类:

         BootStrap类加载器也是Java类,因为Java类的类加载器本身也是要被类加载器加载的,显然必须有第一个类加载器不是Java类,这个正是BootStrap,使用C/C++代码写的,已经封装到JVM内核中了,而ExtClassLoaderAppClassLoaderJava类。

         ExtClassLoader

         AppClassLoader

2、类加载器的属性结构图及原理——双亲委派模型

Java类加载器详解&双亲委派模式_第1张图片

类加载器的委托机制-加载原理:

      1每个类加载器加载类时,又先委托给其上级类加载器当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则会抛出ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild()方法。例如:如上图所示:MyClassLoader->AppClassLoader->Ext-ClassLoader->BootStrap.自定定义的MyClassLoader1首先会先委托给AppClassLoader,AppClassLoader会委托给ExtClassLoader,ExtClassLoader会委托给BootStrap,这时候BootStrap就去加载,如果加载成功,就结束了。如果加载失败,就交给ExtClassLoader去加载,如果ExtClassLoader加载成功了,就结束了,如果加载失败就交给AppClassLoader加载,如果加载成功,就结束了,如果加载失败,就交给自定义的MyClassLoader1类加载器加载,如果加载失败,就报ClassNotFoundException异常,结束。

           这里需要注意的是上述三个JDK提供的类加载器虽然是父子类加载器关系,但是没有使用继承,而是使用了组合关系。

          ——上述过程即双亲委派模型:优点是java的类加载器一起具备了一种带优先级的层次关系,越是基础的类,越是被上层的类加载器进行加载,保证了java程序的稳定运行


2如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器来加载类B

3可以直接调用ClassLoader.loadClass(StringclassName)方法来指定某个类加载器去加载某个类

4)首先当前线程的类加载器去加载线程中的第一个类(当前线程的类加载器:Thread类中有一个get/setContextClassLoader(ClassLoadercl);方法,可以获取/指定本线程中的类加载器)

3、例子:

Java类加载器详解&双亲委派模式_第2张图片

输出结果:

Java类加载器详解&双亲委派模式_第3张图片

note

1因为System类,ListMap等这样的系统提供jar类都在jre/lib/rt.jar中,所以由BootStrap类加载器加载,因为BootStrap是祖先类,不是Java编写的,所以打印出classnull

2)ClassLoaderTest.java打包成.jar文件,后将.jar文件拷贝到Java的安装目录中的Java/jre7/lib/ext/目录下,结果ClassLoaderTest的类加载器变成了ExtClassLoader,如下:

Java类加载器详解&双亲委派模式_第4张图片

二、自定义类加载器

1、自定义的类加载器默认的都是将挂载到系统类加载器的最低端AppClassLoader

loadClass(name,false)方法的源代码:

Java类加载器详解&双亲委派模式_第5张图片

执行流程是:每个类加载器:loadClass→findClass→defineClass.

          findClass这个方法就是根据name来查找到class文件,在loadClass方法中用到,所以我们只能重写这个方法了,只要在这个方法中找到class文件,再将它用defineClass方法返回一个Class对象即可。defineClass这个方法很简单就是将class文件的字节数组编程一个class对象,这个方法肯定不能重写,内部实现是在C/C++代码中实现的

2、自定义类加载器实现

1)首先,定义需要加载的一个类:ClassLoaderAttachment.java,编译成ClassLoaderAttachment.class文件,放到工程目录下。

Java类加载器详解&双亲委派模式_第6张图片

2)定义自定义类加载器

Java类加载器详解&双亲委派模式_第7张图片

3)测试类:

Java类加载器详解&双亲委派模式_第8张图片

输出结果:


note

        因为loadClass方法在使用系统类加载器AppClassLoader的时候需要传递全称(包括包名),我们传递ClassLoaderAttachment的话,AppClassLoader也是没有找到这个ClassLoaderAttachment,所以还是MyClassLoader处理了。      

        如果改成:

Java类加载器详解&双亲委派模式_第9张图片

结果:



例子中class文件可以加密,具体可参考文章:

http://www.wjdiankong.cn/java高新技术第一篇:类加载器详解/





 

你可能感兴趣的:(java)