当前位置:网站首页>自定义类加载器加载网络Class
自定义类加载器加载网络Class
2022-07-07 04:22:00 【cristianoxm】
一、JDK 默认提供了如下三种ClassLoader
- BootStrap ClassLoader:称为启动类加载器,C++实现的,是Java类加载层次中最顶层的类加载器(JVM启动后初始化的),负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等;
- ExtensionClassLoader:称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。该加载器是有java实现的,由Bootstrploader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrploader;
- AppClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。 注:除了这三种外,
jdk允许自定义类加载器;
二、双亲委派
ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(BootstrapClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。 当一个ClassLoader实例需要加载某个类时,它会试图自下而上检查(检查父类加载器)类是否已经加载过,如果某个加载器已经加载该类则直接返回该类对象,直到bootstrap ClassLoader。然后由上至下依次加载类,首先由最顶层的类加载器BootstrapClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给AppClassLoader进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。
为什么要使用双亲委托这种模型呢?
因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时就被引导类加载器(BootstrcpClassLoader)加载,所以用户自定义的ClassLoader永远也无法加载一个自己写的String,除非你改变JDK中ClassLoader搜索类的默认算法。
JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。
三、自定义classloade
要想自定义classloader我们需要通过继承java.lang.ClassLoader类。该类中有几个重要方法,但如果想遵循双亲委托机制,则只需要重写findClass方法
;如果要改变双亲委派,则重写loadClass方法
。
- 以遵循双亲委托机制,并加载网络的class为例子
//包名很重要,自定义类加载器中,需要指定全类名
package com;
public class Hello {
public void say(){
System.out.println("hello");
}
public void say1(){
System.out.println("hello1");
}
public void say2(){
System.out.println("hello2");
}
}
将以上编译成.class文件,在放在远程服务器上。如下
@Slf4j
public class CustomClassLoader extends ClassLoader{
private final String classUrl;
public CustomClassLoader(String classUrl) {
super();
this.classUrl = classUrl;
}
/* classLoader时会先根据委派模型在父类加载器中加载,如果加载失败则会加载当前加载器的findClass方法来加载,因此我们自定义的类加载器只需要继承ClassLoader,并覆盖findClass方法 */
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class clazz = null;//this.findLoadedClass(name); // 父类已加载
//if (clazz == null) { //检查该类是否已被加载过
byte[] classData = getClassData(className(name)); //根据类的二进制名称,获得该class文件的字节码数组
if (classData == null) {
throw new ClassNotFoundException();
}
//其中defineClass方法可以把二进制流字节组成的文件转换为一个java.lang.Class
clazz = defineClass(name,classData, 0, classData.length); //将class的字节码数组转换成Class类的实例
return clazz;
}
//根据类的二进制名称,从网络中获得该class文件的字节码数组
private byte[] getClassData(String name) {
log.info(name);
InputStream is = null;
try {
byte[] buff = new byte[1024*4];
int len;
URL url=new URL(this.classUrl+name+".class");
is = url.openStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while((len = is.read(buff)) != -1) {
baos.write(buff,0,len);
}
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
return null;
}
private String className(String name) {
String[] split = name.split("\\.");
return split[split.length-1];
}
public static void main(String[] args) {
try {
String rootUrl = "http://10.10.10.14:8080/localfile/com/";
CustomClassLoader customClassLoader = new CustomClassLoader(rootUrl);
String classname = "com.Hello";//全类名
Class<?> clazz = customClassLoader.findClass(classname);
log.info("ClassLoader:{} ", clazz.getClassLoader()); //打印类加载器
Object newInstance = clazz.getDeclaredConstructor().newInstance();//构建对象
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
m.invoke(newInstance);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
边栏推荐
- 【webrtc】m98 screen和window采集
- Solution: could not find kf5 (missing: coreaddons dbusaddons doctools xmlgui)
- What is the difference between TCP and UDP?
- Weibo publishing cases
- @component(““)
- 三、高质量编程与性能调优实战 青训营笔记
- leetcode:105. 从前序与中序遍历序列构造二叉树
- Leetcode sword finger offer brush questions - day 20
- 即刻报名|飞桨黑客马拉松第三期等你挑战
- vus.SSR在asynData函数中请求数据的注意事项
猜你喜欢
What are the positions of communication equipment manufacturers?
外包干了三年,废了...
leetcode:105. 从前序与中序遍历序列构造二叉树
English translation is too difficult? I wrote two translation scripts with crawler in a rage
Leetcode-543. Diameter of Binary Tree
IO stream file
The annual salary of general test is 15W, and the annual salary of test and development is 30w+. What is the difference between the two?
二、并发、测试笔记 青训营笔记
How to * * labelimg
Redis data migration
随机推荐
JSON introduction and JS parsing JSON
After 95, Alibaba P7 published the payroll: it's really fragrant to make up this
通信设备商,到底有哪些岗位?
A concurrent rule verification implementation
Deep learning Flower Book + machine learning watermelon book electronic version I found
Leetcode-543. Diameter of Binary Tree
Flutter riverpod is comprehensively and deeply analyzed. Why is it officially recommended?
misc ez_ usb
L'externalisation a duré trois ans.
探索Cassandra的去中心化分布式架构
Write CPU yourself -- Chapter 9 -- learning notes
【性能压测】如何做好性能压测?
【斯坦福计网CS144项目】Lab4: TCPConnection
Route jump in wechat applet
numpy中dot函数使用与解析
Outsourcing for four years, abandoned
3、 High quality programming and performance tuning practical youth training camp notes
pytorch 参数初始化
About some details of final, I have something to say - learn about final CSDN creation clock out from the memory model
Live online system source code, using valueanimator to achieve view zoom in and out animation effect