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

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 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);
    }
}

然后查看测试结果

可以看到编写成功了

相关文章
|
16天前
|
Java
让星星⭐月亮告诉你,自定义定时器和Java自带原生定时器
定时器是一种可以设置多个具有不同执行时间和间隔的任务的工具。本文介绍了定时器的基本概念、如何自定义实现一个定时器,以及Java原生定时器的使用方法,包括定义定时任务接口、实现任务、定义任务处理线程和使用Java的`Timer`与`TimerTask`类来管理和执行定时任务。
37 3
|
3月前
|
Java 应用服务中间件 Windows
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
|
3天前
|
Java 开发者 Spring
[Java]自定义注解
本文介绍了Java中的四个元注解(@Target、@Retention、@Documented、@Inherited)及其使用方法,并详细讲解了自定义注解的定义和使用细节。文章还提到了Spring框架中的@AliasFor注解,通过示例帮助读者更好地理解和应用这些注解。文中强调了注解的生命周期、继承性和文档化特性,适合初学者和进阶开发者参考。
27 14
|
10天前
|
安全 Java
如何在 Java 中创建自定义安全管理器
在Java中创建自定义安全管理器需要继承SecurityManager类并重写其方法,以实现特定的安全策略。通过设置系统安全属性来启用自定义安全管理器,从而控制应用程序的访问权限和安全行为。
|
1月前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
51 2
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
|
18天前
|
运维 监控 搜索推荐
阿里大鱼进行发短信业务---使用详细步骤-Java操作
这篇文章详细介绍了如何在Java中使用阿里大鱼服务来发送短信,包括开通短信服务、签名和模板管理,以及具体的Java开发步骤和代码示例。
36 0
阿里大鱼进行发短信业务---使用详细步骤-Java操作
|
22天前
|
消息中间件 存储 Java
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
30 3
|
2月前
|
IDE Java 开发工具
java自定义异常20
java自定义异常20
25 3
|
2月前
|
Java 编译器 程序员
Java注解,元注解,自定义注解的使用
本文讲解了Java中注解的概念和作用,包括基本注解的用法(@Override, @Deprecated, @SuppressWarnings, @SafeVarargs, @FunctionalInterface),Java提供的元注解(@Retention, @Target, @Documented, @Inherited),以及如何自定义注解并通过反射获取注解信息。
Java注解,元注解,自定义注解的使用
|
26天前
|
算法 Java 测试技术
数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题
文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。
15 0