当前位置:网站首页>自定义类加载器
自定义类加载器
2022-08-08 06:27:00 【写做四月一日的四月一日】
目录
类加载器
| 类加载器名 | 加载路径 |
| 启动类加载器(Bootstrap ClassLoader) | %JAVM_HOME%\jre\lib |
| 扩展类加载器(Extension ClassLoader) | %JAVM_HOME%\jre\lib\ext |
| 应用类加载器(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",类加载完成。
边栏推荐
猜你喜欢

Lettcode链表OJ题分享以及讲解

在ENSP中配置DHCP服务器

线程P01——进程 并发 并行 线程的使用

win11+MX250+CUDA Tookit 10.1 update 2

Stack queue OJ question sharing and explanation

Leetcode topic sharing and explanation

tcpdump进行DNS抓包

Nine common interfaces for implementing sequence table in C language

acwing 第63场周赛【2022.08.06】

关于剪枝对象的分类(weights剪枝、神经元剪枝、filters剪枝、layers剪枝、channel剪枝、对channel分组剪枝、Stripe剪枝)
随机推荐
【图形学】16 光照模型(一、理论与公式)
NVIDIA CUDA Highly Parallel Processor Programming (6): Parallel Mode: Convolution
3.关于剪枝论文的分类和整理(随笔)
霍夫曼树(赫夫曼树、哈夫曼树)
Dropout、剪枝、正则化有什么关系?什么是Dropout?
C# Unicode (Universal Code) text conversion
Leetcode topic sharing and explanation
acwing 第63场周赛【2022.08.06】
【EagleEye】2020-ECCV-EagleEye: Fast Sub-net Evaluation for Efficient Neural Network Pruning-论文详解
datetime模块,os模块,sys模块,json模块
Math工具类的ceil()、floor()、round()方法源码阅读
Unity HDRP中代码动态修改天空盒以及其他环境参数
P21 美颜相机的实现——提速,重绘,撤回
OSPF动态配置网络环境
【图形学】17 光照模型(二、漫反射的Shader实现)
[Unity] GPU动画实现(三)——材质合并
线程P01——进程 并发 并行 线程的使用
Writing of Makefile (detailed example)
VS2015MFC+SQLService版本的选择
Binary tree traversal and method