专栏首页博岩Java大讲堂Java虚拟机--自定义类加载器

Java虚拟机--自定义类加载器

如何定义一个类加载器

前面,我们介绍了类加载器的原理,以及类加载的源码。

本篇,我们结合前面所说的内容,来自定义一个类加载器,以及使用自定义的类加载来完成类加载操作。

在展示代码之前,我们来探讨一个问题,为什么要自定义类加载?

什么场景下需要我们来自定义类加载器加载我们所需要的类?

(1)被加密的.class文件,为了安全保证你.class文件进行了加密处理,在程序运行的过程中,你需要解密后再进行操作。此时,就需要自定义一个类加载器来完成.class文件的解密操作,解密完成后再进行类加载;

(2).class文件不在默认的类加载路径下(可参考之前的文章,看下类路径都包含哪些),如果想要加载则需要自己定义类加载来完成,例如:.class文件内容存放在了数据库、网络地址(ftp服务器)等;

(3)对于非.class的文件,需要转为Java类,就需要自定义类加载器,例如:JSP文件。

如果你还能想到别的场景,请在下面的评论中指出!!!

代码展示

通常情况下,在自定义类加载器时,会直接覆盖ClassLoader的findClass()方法并编写加载规则(为什么要覆盖此方法,前面的文章中有解答),取得要加载类的字节码后转换成流,然后调用defineClass()方法生成类的Class对象,简单例子如下:

public class ClassLoaderTest extends ClassLoader{

    private String loaderRootPath;

    public ClassLoaderTest(ClassLoader parent) {
        super(parent);
    }

    public ClassLoaderTest(String loaderRootPath) {
        this.loaderRootPath = loaderRootPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try{
            String filePath = loaderRootPath + name.replace('.', File.separatorChar) + ".class";
            //指定读取磁盘上的某个文件夹下的.class文件:
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            byte[] bytes = new byte[fis.available()];
            fis.read(bytes);
            //此处可以对字节数组进行解密操作:
            //省略。。。。
            //调用defineClass方法,将字节数组转换成Class对象
            Class<?> clazz = this.defineClass(name, bytes, 0, bytes.length);
            System.out.println(clazz.getClassLoader());
            return clazz;
        }catch (FileNotFoundException e){
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return super.findClass(name);
    }

    public static void main(String[] agrs) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        try {
            ClassLoaderTest classLoaderTest = new ClassLoaderTest("d:/");
            classLoaderTest.loadClass("ObjectTest1");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

如果,你在开发工具(例如:idea)里创建的测试类,那么在编译完成后,一定要把classpath下的文件删除,否则类加载机制会使用应用类加载器进行类加载。

测试结果如下:

没删除classpath下的类的结果:sun.misc.Launcher$AppClassLoader@8fd9b4d

删除classpath下的类的结果:ClassLoaderTest@280ae735

对于自定义类加载,还有另一种更为简单的方案,就是继承URLClassLoader类。

为什么说继承URLClassLoader类更为简单?(URLClassLoader源码讲解)

在URLClassLoader类中,已经帮我们实现了获取字节数组的逻辑,并将字节数组转换成Class对象。

public class ClassLoaderTest1 extends URLClassLoader {

    public ClassLoaderTest1(URL[] urls) {
        super(urls);
    }

    public ClassLoaderTest1(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public ClassLoaderTest1(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(urls, parent, factory);
    }

    public static void main(String[] agrs) {
        String rootDir="D:/";
        File file = new File(rootDir);
        URI uri=file.toURI();
        try {
            URL[] urls= new URL[]{uri.toURL()};
            ClassLoaderTest1 loader = new ClassLoaderTest1(urls);
            Class clazz = loader.loadClass("ObjectTest1");
            System.out.println(clazz.getClassLoader());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

测试结果:

ClassLoaderTest1@6469adc7

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java虚拟机--类加载器如何加载一个Class文件

    贾博岩
  • Java虚拟机--线程上下文类加载器

    贾博岩
  • Java-SPI机制

    贾博岩
  • 面试官:谈谈类加载器吧,你有没有看过类加载器的源码?

    2)我们的jsp会被转换成servlet,而我们的serlvet是一个java文件,会被编译成class文件

    程序员追风
  • Groovy、热部署和热加载(自定义类加载器)及spring loaded 部分源码分析

    优点:不需要重启tomcat服务器,如果一个tomcat多个项目,不必因为tomcat停止而停止其他的项目。

    猎户星座1
  • LeetCode 1395. 统计作战单位数(蛮力法)

    来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/count-number-of-teams 著作权归...

    Michael阿明
  • go的非侵入式接口

    什么是接口 接口就是一组方法的集合。比如下面这个例子,几何图形接口就包含了面积与周长两个方法,对于任何实现了这两个方法的type,都属于几何图形。 type G...

    李海彬
  • 轻松看懂机器学习十大常用算法

    通过本篇文章可以对ML的常用算法有个常识性的认识,没有代码,没有复杂的理论推导,就是图解一下,知道这些算法是什么,它们是怎么应用的,例子主要是分类问题。

    杨熹
  • 机器学习十大常用算法小结

    机器学习十大常用算法小结 通过本篇文章可以对ML的常用算法有个常识性的认识,没有代码,没有复杂的理论推导,就是图解一下,知道这些算法是什么,它们是怎么应用的,例...

    Angel_Kitty
  • 常识图解-机器学习十大常用算法

    通过本篇文章可以对ML的常用算法有个常识性的认识,没有代码,没有复杂的理论推导,就是图解一下,知道这些算法是什么,它们是怎么应用的,例子主要是分类问题。 每个算...

    机器人网

扫码关注云+社区

领取腾讯云代金券