Java自定义类加载器的编写步骤

简介: Java自定义类加载器的编写步骤

Java自定义类加载器的编写步骤

两个问题

  1. 为什么要使用自定义类加载器呢?
    Java的class很容易就被反编译,那么我们需要做加密,那么我们加载这个类的时候就需要用到自定义加载器。并且如果需要加载的类不在classPath下,而是在硬盘其他地方或者是网络上,那么同样也需要用到自定也需要用到自定义类加载器
  2. 什么情况下使用自定义类加载器?
  1. 加密:Java代码容易被反编译,那么不想要人家看到源代码的时候就需要进行加密。加密之后自带的类加载器不能使用,那么就需要使用到自定义类加载器
  2. 非标准来源加载代码:比如硬盘其他路径上的class文件,或者网络传过来的class文件

如何自定义类加载器

我们先来看 sun.misc.Launcher 类中的源码,以 AppClassloader 为例,首先人家继承了 java.net.URLClassLoader 并且实现了加载类的 loadClass 方法,如图

然而我们查看 java.net.URLClassLoader 时我们可以看到,最终人家继承自 java.lang.ClassLoader,如:

public class URLClassLoader extends SecureClassLoader implements Closeable // 继承自 SecureClassLoader
public class SecureClassLoader extends ClassLoader // 然后 SecureClassLoader 继承自 ClassLoader

注意看 AppClassloader 中的 loadClass 人家在调用父类的 loadClass 方法,父类的 loadClass 方法中调用了 findClass 方法

而 findClass 方法会抛出一个没有找到类的异常,并表示需要子类从写这个方法

那么我们根据这个思路新增一个自定义类加载器并继承 java.lang.ClassLoader。

package com.xiaohh.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
 * 自定义类加载器
 */
public class XiaoHHClassLoader extends ClassLoader {
    /**
     * 查找 class
     * @param name class 的名字
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // Class 类的存放路径
        String resource = "C:/test/";
        // 按照路径找到需要加载的 class 文件
        File source = new File(resource, name.replace('.', '/').concat(".class"));
        // 判断文件是否存在
        if (!source.exists()) {
            throw new ClassNotFoundException(name + "is not found. ");
        }
        FileInputStream fis = null;
        try {
            // 将文件以流的方式加载到内存中
            fis = new FileInputStream(source);
            // 将文件转换为字节数组
            byte[] bytes = new byte[fis.available()];
            fis.read(bytes);
            // 定义类并返回,此步骤没有抛出异常表示完成加载
            return super.defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            // 处理方式可以更加严谨,请自行处理
            throw new ClassNotFoundException(name + "is not found. ");
        } finally {
            // 关闭资源
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这段代码定义了一个名为 XiaoHHClassLoader 的自定义类加载器,我们注意一下这段代码

return super.defineClass(name, bytes, 0, bytes.length);

这段代码调用了 ClassLoader 中的 defineClass 方法,作用是将字节数组解析成一个 Class 实例

到此为止我们的自定义类加载器就编写完成了,我们现在编写一个类来测试一下

package com.xiaohh.customer;
public class Hello {
    public void sayHello() {
        System.out.println("Hello");
    }
}

将这个文件编译之后放在 C:\test\com\xiaohh\customer 的文件夹中

注意在自己的项目中不要出现这个class!!!

然后我们写一个测试方法

package com.xiaohh.test;
import java.lang.reflect.InvocationTargetException;
public class TestMain {
    public static void main(String[] args)
            throws ClassNotFoundException, IllegalAccessException,
            InstantiationException, InvocationTargetException, NoSuchMethodException {
        // 获取自定的类加载器
        ClassLoader loader = new XiaoHHClassLoader();
        // 加载硬盘上的 class 文件
        Class<?> helloClass = loader.loadClass("com.xiaohh.customer.Hello");
        // 获得这个类的对象,因为只有一个默认的无参构造
        Object hello = helloClass.getConstructors()[0].newInstance();
        // 查看类的信息
        System.out.println("Class name: " + hello.getClass().getName());
        System.out.println("Class loader: " + hello.getClass().getClassLoader()); // 查看使用的是哪个类加载器
        // 调用这个类的方法
        // helloClass.getMethods()[0].invoke(hello);
        helloClass.getMethod("sayHello").invoke(hello);
    }
}

然后查看测试结果

可以看到编写成功了

相关文章
|
1月前
|
Java Spring 容器
【Java】Spring如何扫描自定义的注解?
【Java】Spring如何扫描自定义的注解?
36 0
|
1月前
|
前端开发 Java API
类加载器“如果我定义了一个类名与Java核心类类名相同,那它还能被加载吗?”
类加载器“如果我定义了一个类名与Java核心类类名相同,那它还能被加载吗?”
|
17天前
|
Java
Java配置大揭秘:读取自定义配置文件的绝佳指南
Java配置大揭秘:读取自定义配置文件的绝佳指南
16 0
Java配置大揭秘:读取自定义配置文件的绝佳指南
|
21天前
|
NoSQL Java Redis
Java自定义线程池的使用
Java自定义线程池的使用
|
24天前
|
Java
在Java中,定义一个接口的步骤如下
【4月更文挑战第6天】在Java中,定义一个接口的步骤如下
5 1
|
1月前
|
Java API Maven
email api java编辑方法?一文教你学会配置步骤
在Java开发中,Email API是简化邮件功能的关键工具。本文指导如何配置和使用Email API Java:首先,在项目中添加javax.mail-api和javax.mail依赖;接着,配置SMTP服务器和端口;然后,创建邮件,设定收件人、发件人、主题和正文;最后,使用Transport.send()发送邮件。借助Email API Java,可为应用添加高效邮件功能。
|
1月前
|
Java
java 自定义注解 实现限流
java 自定义注解 实现限流
14 1
|
1月前
|
安全 前端开发 Java
【Java】探究Java中的类加载器
【Java】探究Java中的类加载器
17 0
|
1月前
|
Java 网络安全 开发者
【Docker】5、Dockerfile 自定义镜像(镜像结构、Dockerfile 语法、把 Java 项目弄成镜像)
【Docker】5、Dockerfile 自定义镜像(镜像结构、Dockerfile 语法、把 Java 项目弄成镜像)
44 0
|
2月前
|
Java
[Java]自定义注解
[Java]自定义注解
43 0