栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

自定义类加载器

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自定义类加载器

目录

类加载器

双亲委派机制

双亲委派机制的优点

双亲委派机制源码简介

自定义类加载 

一、写一个测试用类

二、写一个自定义类加载器


类加载器
类加载器名加载路径
启动类加载器(Bootstrap ClassLoader)%JAVM_HOME%jrelib
扩展类加载器(Extension ClassLoader)%JAVM_HOME%jrelibext
应用类加载器(AppClassLoader)%classpath%

自定义类加载器:扩展于ClassLoader类,可以自定义路径。

双亲委派机制

当使用类加载器时,会按照自定义类加载器->应用类加载器->扩展类加载器->启动类加载器的方式向上委托父类加载来加载需要加载的类,如果加载不到,再由子类加载器来加载,最后都没有加载到则抛出ClassNotFoundException异常。

双亲委派机制的优点

保证了安全性。

举例:如果不使用双亲委派机制,开发者可以自定义一个java.lang.String类来覆盖官方的java.lang.String,使用自定义类加载器完成类加载。密码一般都是以字符串形式存储的,开发者可以在自定义的String类型中完成诸如将密码发送给自己等操作。使用双亲委派机制,当使用自定义类加载器加载自定义的java.lang.String类时,最终会通过双亲委派机制委托启动类加载器完成官方的java.lang.String加载,无法覆盖,保证了安全性。

双亲委派机制源码简介

查看Classloader类的源码,根据注释说明可以知道loadClass()方法是完成类加载的方法。

loadClass()源码查看

 查看findClass()方法

源码中只是抛出了一个FlassNotFoundException异常,我们需要重写这个方法。

自定义类加载 

当官方提供的三个类加载器都无法满足我们的需求,我们就需要自定义类加载器。如实现框架时,我们用到了动态代理模式来生成一个新的代理类,这个代理类就需要通过自定义类加载器来加载到程序中来。

根据之前的分析,我们实现一个类加载器只需要两步:

1)写一个类继承Classloader类;

2)重写findClass()方法。

一、写一个测试用类

这个类在官方的三个加载器都加载不到的路径,并使用javac命令编译这个类。

为了方便起见,我只写了一个printHello()方法,在方法中打印一个"hello"。

 

public class TestEntity{
	public void printHello(){
		System.out.println("hello");
	}
}

二、写一个自定义类加载器
public class MyClassLoader extends ClassLoader{
    //这个自定义类加载器加载的路径
    private String path = "F:\java_work\Java_project\classloaderTestEntity\";
    //类文件的后缀名
    private String suffix = ".class";
    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
        //输入流,用于读入class文件
        BufferedInputStream bis = null;
        //输出流,用于承接class文件内容,并生成一个byte[]数组
        ByteArrayOutputStream bos = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(path + name + suffix));
            bos = new ByteArrayOutputStream();
            //记录当前读入的长度
            int length = 0;
            //存放读入数据的临时数组
            byte[] temp = new byte[1024];
            //读入class文件并写到输出流
            while ((length = bis.read(temp)) != -1){
                bos.write(temp,0,length);
            }
            //获取到class文件的byte[]数组
            byte[] classDataArray = bos.toByteArray();
            //通过defineClass()方法来将byte[]数组转为一个class类
            return defineClass(name,classDataArray,0,classDataArray.length);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (null != bis){
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != bis){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //最后还没有找到出ClassNotFoundException异常
        return super.findClass(name);
    }
}

三、测试能否将测试用类加载到程序中

public class TestApp {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //获取自定义类加载器
        MyClassLoader myClassLoader = new MyClassLoader();
        //加载TestEntity类
        Class clazz = myClassLoader.loadClass("TestEntity");
        //实例化TestEntity类
        Object obj = clazz.newInstance();
        //调用printHello方法
        Method[] methods = obj.getClass().getDeclaredMethods();
        for (Method method : methods) {
            if ("printHello".equals(method.getName())){
                method.invoke(obj);
            }
        }
    }
}

运行结果

成功打印了"hello",类加载完成。

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/992218.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号