Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 451|回复: 0

开发交流:JVM--classLoader 说明一

[复制链接]

该用户从未签到

发表于 2011-10-24 09:48:26 | 显示全部楼层 |阅读模式
JVM的体系结构




从图上可以看出,JVM体系结构中,主要有以下几个部分:
1.java class文件
2.class文件加载系统
3.运行期数据区(java栈、堆、方法区、PC寄存器、本地方法区)
4.执行引擎
5.本地方法接口
6.本地方法库


JVM的classLoader体系-1
命名空间:
?不同的类加载器具有不同的命名空间
?同一命名空间内,类的名称具有惟一性
?同一命名空间内,类之间可以直接交互
?不同命名空间之间,除非显示的提供交互的机制,是不能交互的

类加载器:
?启动类加载器(Bootstrap classloader)
?扩展类加载器(Extended classloader)
?系统类加载器(Application classloader)
?Bootstrap加载Extended和Application,Extended的父类为Bootstrap,由于Bootstrap是由C++语言编写,所以Extended的父类为null,Bootstrap在加载Application的时候,将其父类设置为Extended

每个类加载器所加载文件的目录:
?每个类加载器所加载文件的目录:
?可以通过方法:System.getProperty(String str);方法获得
?Bootstrap:   sun.boot.class.path
?Extended:    java.ext.dirs
?Application:java.class.path

类加载器的委派模型:
?类加载器总是委托其父类去加载所需要的文件
?如果一个文件A引用另一个文件B,在没有自定义加载B的加载器的情况下,B类只能由A类的加载器或者其父类加载


JVM的classLoader体系-2

在“JVM的classLoader体系-1”,总结了jvm的classloader一些基本的内容,肯定有很多不足的地方,还请大家指点,现在对jvm类加载机制进行一下测试:
1.建立测试文件Main.java和Test.java
Main.java负责打印出Main.java和Test.java的类加载器)

Main.java代码:
public class Main {   
public static void main(String args[]){   
System.out.print("Main's classLoader is ");   
System.out.println(Main.class.getClassLoader());   
System.out.print("Test's classLoader is ");   
System.out.print(Test.class.getClassLoader());   
}   
}  

Test.java(do nothing):

Test.java代码:
public class Test {   
}  
2.测试准备
在F盘下面建立一个javasource的文件夹,并将此文件夹加到CLASSPATH的value中,运行结果如下:
Main's classLoader is sun.misc.Launcher$AppClassLoader@19821f(Main.class的加载器)
Test's classLoader is sun.misc.Launcher$AppClassLoader@19821f(Test.class的加载器)
3.classLoader加载机制的测试:
3.1测试01-文件存放的位置
?Javasource目录下:
?Main.class
?Test.class
?Jdk\jre\ib\ext\classes目录下:
?Main.class
?Test.class
?Jdk\jre\classes目录下:
?Main.class
?Test.class
3.2测试01-结果
?Main's classLoader is null
?Test's classLoader is null
3.3测试01-结果分析
在运行java Main的时候,由Application ClassLoader加载所需要的类,在加载的过程中,Application ClassLoader首先将加载任务委派给其父类Extended ClassLoader,Extended ClassLoader又将加载的任务委派给Bootstrap ClassLoader,由于在Bootstrap ClassLoader下面有Main.class文件,所以BootStrap ClassLoader负责类Main的加载。在Main.class中,引用了Test.class,在默认的情况下,由加载Main.class的类加载器加载Test.class,所以Test.class的类加载器也是null
3.2测试02-文件存放的位置
?Javasource目录下:
?Main.class
?Test.class
?Jdk\jre\ib\ext\classes目录下:
?Main.class
?Test.class
?Jdk\jre\classes目录下:
?Main.class
3.2测试02-测试结果
?Main's classLoader is null
?Test's classLoader is Exception in thread "main" java.lang.NoClassDefFoundError:
    Test  at Main.main(Main.java:8)
3.2测试02-测试结果分析
由于Bootstrap ClassLoader下面有Main.class,所以由Bootstrap ClassLoader负责加载Main.class,在默认的情况下,Main.class所引用的类将由Bootstrap加载,由于Bootstrap所加载的目录下的Test.class被删除了,所以出来NoClassDefFoundError的现象
3.3测试03-文件存放的位置
?Javasource目录下:
?Main.class
?Test.class
?Jdk\jre\ib\ext\classes目录下:
?Main.class
?Test.class
?Jdk\jre\classes目录下:
?Test.class
3.3测试03-测试结果
?Main's classLoader is sun.misc.Launcher$ExtClassLoader@126b249
?Test's classLoader is null
3.3测试03-测试结果分析
Main.class由ExtClassLoader加载,在默认的情况下,Test.class也应该由ExtClassLoader加载,ExtClassLoader首先委派其父类Bootstrap ClassLoader加载,由于Bootstrap所加载文件下有Test.class,所以由Bootstrap负责加载Test.class
3.4测试04-文件存放的位置
?Javasource目录下:
?Main.class
?Test.class
?Jdk\jre\ib\ext\classes目录下:
?Main.class
?Test.class
?Jdk\jre\classes目录下:
3.4测试04-测试结果

?Main's classLoader is sun.misc.Launcher$ExtClassLoader@182f0db
?Test's classLoader is sun.misc.Launcher$ExtClassLoader@182f0db
3.4测试04-测试结果分析
思路如测试01
3.5测试05-文件存放的位置
?Javasource目录下:
?Main.class
?Test.class
?Jdk\jre\ib\ext\classes目录下:
?Main.class
?Jdk\jre\classes目录下:
3.5测试05-测试结果

Main's classLoader is sun.misc.Launcher$ExtClassLoader@126b249
Test's classLoader is Exception in thread "main" java.lang.NoClassDefFoundError:
Test
        at Main.main(Main.java:8)
Caused by: java.lang.ClassNotFoundException: Test
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at sun.misc.Launcher$ExtClassLoader.findClass(Launcher.java:229)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
        ... 1 more
3.5测试05-测试结果分析
思路如测试02
3.6测试06-文件存放的位置
?Javasource目录下:
?Main.class
?Test.class
?Jdk\jre\ib\ext\classes目录下:
?Test.class
?Jdk\jre\classes目录下:
3.6测试06-测试结果
?Main's classLoader is sun.misc.Launcher$AppClassLoader@ad3ba4
?Test's classLoader is sun.misc.Launcher$ExtClassLoader@126b249
3.6测试06-测试结果分析
思路如测试03

4.总结
1.从测试结果中可以看出,类加载器在加载应用程序的class文件时,首先委托其父类进行加载,在父类加载失败的情况下,从由自己去加载。
2.在默认情况下,类A引用类B,那么类B的加载由类A的加载器或者类A加载器的父类来完成


自定义ClassLoader
Customclassloader代码

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Hashtable;

public class CustomClassLoader extends ClassLoader {
        /**
         * 从来存放所加载的类
         */
        private Hashtable<String, Class<?>> classes = new Hashtable<String, Class<?>>();

        /**
         * 要加载文件的目录
         */
        private String rootDir;

        /**
         * 将此类加载器的父类设置为加载此类的类加载器
         */
        public CustomClassLoader(String rootDir) {
                super(CustomClassLoader.class.getClassLoader());
                if (rootDir == null || rootDir.trim().equals("")) {
                        throw new IllegalArgumentException("您说输入的文件目录为空");
                }
                this.rootDir = rootDir;
        }

        /**
         * 根据类名加载类文件
         */
        public Class<?> loadClass(String className) throws ClassNotFoundException {
                return findClass(className);
        }

        /**
         * 根据类名查找类
         */
        public Class<?> findClass(String className) {
                byte classByte[];
                Class<?> result = null;

                result = (Class<?>) classes.get(className);
                if (result == null) {
                        try {//首先通过系统类加载器加载
                                return findSystemClass(className);
                        } catch (Exception e) {

                        }
                }else{
                        return result;
                }

                //通过自定义类加载器加载类文件
                try {
                        String classPath = rootDir + "\\"
                                        + className.replace('.', File.separatorChar) + ".class";
                        classByte = loadClassData(classPath);
                        result = defineClass(className, classByte, 0, classByte.length,
                                        null);
                        if(result==null){
                                throw new ClassNotFoundException();
                        }
                        classes.put(className, result);
                        return result;
                } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                }

        }

        // 负责加载class文件的数据信息
        private byte[] loadClassData(String className) throws IOException {
                File f;
                f = new File(className);
                int size = (int) f.length();
                byte buff[] = new byte[size];
                FileInputStream fis = new FileInputStream(f);
                DataInputStream dis = new DataInputStream(fis);
                dis.readFully(buff);
                dis.close();
                return buff;
        }
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2025-1-10 22:37 , Processed in 0.511659 second(s), 48 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表