深入理解Java类加载器(ClassLoader)

一、概念
JDK 默认提供了如下几种ClassLoader

  • List item

    Bootstrp loader
    Bootstrp加载器是用C++语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载%JAVA_HOME%/jre/lib,-Xbootclasspath参数指定的路径以及%JAVA_HOME%/jre/classes中的类。

  • List item

    ExtClassLoader
    Bootstrp loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrp loader.ExtClassLoader是用Java写的,具体来说就是 sun.misc.Launcher$ExtClassLoader,ExtClassLoader主要加载%JAVA_HOME%/jre/lib/ext,此路径下的所有classes目录以及java.ext.dirs系统变量指定的路径中类库。

  • List item

    AppClassLoader
    Bootstrp loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为 ExtClassLoader。AppClassLoader也是用Java写成的,它的实现类是 sun.misc.Launcher$AppClassLoader,另外我们知道ClassLoader中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。

综上所述,它们之间的关系可以通过下图形象的描述:
在这里插入图片描述
普及一点基础知识

(1)rt.jar:Java基础类库,也就是Java doc里面看到的所有的类的class文件,默认就在Root Classloader的加载路径里面的,而在Claspath配置该变量是不需要的;同时jre/lib目录下的其他jar:jce.jar、jsse.jar、charsets.jar、resources.jar都在Root Classloader中
(2)tools.jar:是系统用来编译一个类的时候用到的,即执行javac的时候用到,javac XXX.java实际上就是运行
java -Calsspath=%JAVA_HOME%\lib\tools.jar xx.xxx.Main XXX.java
(3)dt.jar:d是关于运行环境的类库,主要是swing的包 在用到swing时最好加上。

注:dt.jar和tools.jar位于:%Java_Home%\lib\下,而rt.jar位于:%Java_Home%\jre\lib\下。JRE大家都知道是运行Java程序所不可缺少的运行环境,因此rt.jar放在JRE的lib下也就理所应当了。
二、基础
类加载过程详解
JVM将类加载过程分为三个步骤:装载(Load),链接(Link)和初始化(Initialize)
在这里插入图片描述
双亲委派机制(全盘负责委托机制)

某个特定的类加载器在接到加载类的请求时,首先将加载任务委托交给父类加载器,除非指定类加载器,父类加载器又将加载任务向上委托,直到最父类加载器,如果最父类加载器可以完成类加载任务,就成功返回,如果不行就向下传递委托任务,由其子类加载器进行加载。
双亲委派机制的好处:
保证java核心库的安全性(例如:如果用户自己写了一个java.lang.String类就会因为双亲委派机制不能被加载,不会破坏原生的String类的加载)
代理模式:
就是指定了类加载器,是先自己尝试加载,如果无法加载则向上传递。tomcat就是代理模式。

示例代码

//实例
package template;
public class LoaderTest {
	public LoaderTest(){
		System.out.println("创建了新对象");
	}
	public void test() {
		System.out.println("测试方法");
	}
}
//自定义ClassLoader
package classloader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
public class MyClassCloader extends ClassLoader {
    private String rootPath;
    public MyClassCloader(String rootPath){
        this.rootPath = rootPath;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        //check if the class have been loaded
        Class<?> c = findLoadedClass(name);        
        if(c!=null){
            return c;
        }
        //load the class
        byte[] classData = getClassData(name);
        if(classData==null){
            throw new ClassNotFoundException();
        }
        else{
            c = defineClass(name,classData, 0, classData.length);
            return c;
        }    
    }
    private byte[] getClassData(String className){
        String path = rootPath+"/"+className.replace('.', '/')+".class";
        System.out.println(path);
        InputStream is = null;
        ByteArrayOutputStream bos = null;
        try {
            is = new FileInputStream(path);
            bos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int temp = 0;
            while((temp = is.read(buffer))!=-1){
                bos.write(buffer,0,temp);
            }
            return bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                is.close();
                bos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }            
        }
        
        return null;        
    }    

}

//测试类
package template;
import org.junit.Test;
import classloader.MyClassCloader;
public class SpringBeanTest {
	public static void main(String[] args) {
		ClassLoader c  = SpringBeanTest.class.getClassLoader();  //获取Test类的类加载器
        System.out.println(c); //sun.misc.Launcher$AppClassLoader@73d16e93
        ClassLoader c1 = c.getParent();  //获取c这个类加载器的父类加载器
        System.out.println(c1);//sun.misc.Launcher$ExtClassLoader@15db9742
        ClassLoader c2 = c1.getParent();//获取c1这个类加载器的父类加载器
        System.out.println(c2 );//输出null,因为BooStrClassLoader是c编写的
	}
	@Test
    public void testClassLoader() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
		MyClassCloader loader = new MyClassCloader("E:/My folder/JavaTest");
        Class<?> c = loader.loadClass("template.LoaderTest");
        Class ss= Class.forName("template.LoaderTest");
        ss.newInstance();
}

以上资料仅供学习参考,整理不易。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值