jvm解析二(自定义加载器)
程序员文章站
2022-06-07 17:12:43
...
自定义加载器<code>
3个类LoaderTest01.java, LoaderTest02.java,MyClassLoader.java
1, MyClassLoader
2, LoaderTest01
3, LoaderTest02
第一种情况文件按照下面位置放置
运行结果如下:
分析:当执行load(loader02)这句语句的时候,会优先去找它的父加载器loader01, 而loader01又回去找它的父类是系统加载器,系统加载器会根据classpath来查找所要加载的类,发现没有,接着由loader01去加载,loader01加载的时候找到文件执行接下操作,而LoaderTest01里主动使用了new LoaderTest02(), LoaderTest02也会根据上面的方式去找,跟LoaderTest01结果是一样的。
当执行load(loader03)这句语句的时候,由于父类加载器是null默认为根加载器,根加载器会去sun.boot.class.path的里面去找没有找到,最后由loader3自己去加载。
第二种情况文件按照下面位置放置
运行结果如下:
分析:当执行load(loader02)的时候,会优先去找它的父加载器loader01, 而loader01又回去找它的父类是系统加载器,系统加载器会根据classpath来查找所要加载的类,发现没有,接着由loader01去加载,loader01加载的时候找到文件执行接下操作,而LoaderTest01里主动使用了new LoaderTest02(), LoaderTest02也会执行上面同样的步骤, 但是LoaderTest01和LoaderTest02位于2个不同的加载器空间下,而他们之间是互相不可见的(他们的父子关系并不是继承,也有可能是组合,但是他们都是系统加载器的子类,对系统加载器里的资源都是共享的),所以在Loader01加载器加载的时候无法获取LoaderTest02
第三种情况:
运行结果如下:
分析:当执行load(loader02)的时候,会优先去找它的父加载器loader01, 而loader01又回去找它的父类是系统加载器,系统加载器会根据classpath来查找所要加载的类,并在当前目录下发现了这2个类,并执行操作,前2个加载器均为系统加载器,虽然lib1和lib2下2个文件在不同的类加载器空间下,但是实际执行并不需要它们,在系统一级已经执行完毕,而第三个,当执行load(loader03)的时候,父加载器null默认为根加载器,根加载器无法在相应的目录里找到相应的文件,于是交由其他加载器实现,而此时loader03加载器在相应的otherlib3下也无法找到相应的文件于是报错。
3个类LoaderTest01.java, LoaderTest02.java,MyClassLoader.java
1, MyClassLoader
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class MyClassLoader extends ClassLoader{ private String name; private String path; private final String fileType=".class"; public MyClassLoader(String name){ super(); this.name=name; } public MyClassLoader(ClassLoader parent,String name){ super(parent); this.name=name; } @Override public String toString() { return this.name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getFileType() { return fileType; } private byte[] loadClassData(String name) { InputStream in=null; byte [] data=null; ByteArrayOutputStream bs=null; try{ System.out.println("name="+this.name); this.name=this.name.replace(".", "\\"); in=new FileInputStream(new File(path+name+fileType)); bs=new ByteArrayOutputStream(); int k=0; while((k=in.read())!=-1){ bs.write(k); } data=bs.toByteArray(); }catch(Exception e){ e.printStackTrace(); }finally{ try { in.close(); bs.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return data; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte [] data=this.loadClassData(name); return this.defineClass(name, data, 0,data.length); } public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ MyClassLoader loader01=new MyClassLoader("loader01"); loader01.setPath("d:\\loader\\lib1\\"); MyClassLoader loader02=new MyClassLoader(loader01,"loader02"); loader02.setPath("d:\\loader\\lib2\\"); MyClassLoader loader03=new MyClassLoader(null,"loader03"); loader03.setPath("d:\\loader\\otherlib3\\"); load(loader02); load(loader03); } public static void load(ClassLoader loader) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ Class c=loader.loadClass("LoaderTest01"); Object object=c.newInstance(); } }
2, LoaderTest01
public class LoaderTest01 { public LoaderTest01() { System.out.println("LoaderTest01 is loader by :"+this.getClass().getClassLoader()); new LoaderTest02(); } }
3, LoaderTest02
public class LoaderTest02 { public LoaderTest02() { System.out.println("LoaderTest02 is loader by :"+this.getClass().getClassLoader()); } }
第一种情况文件按照下面位置放置
运行结果如下:
分析:当执行load(loader02)这句语句的时候,会优先去找它的父加载器loader01, 而loader01又回去找它的父类是系统加载器,系统加载器会根据classpath来查找所要加载的类,发现没有,接着由loader01去加载,loader01加载的时候找到文件执行接下操作,而LoaderTest01里主动使用了new LoaderTest02(), LoaderTest02也会根据上面的方式去找,跟LoaderTest01结果是一样的。
当执行load(loader03)这句语句的时候,由于父类加载器是null默认为根加载器,根加载器会去sun.boot.class.path的里面去找没有找到,最后由loader3自己去加载。
第二种情况文件按照下面位置放置
运行结果如下:
分析:当执行load(loader02)的时候,会优先去找它的父加载器loader01, 而loader01又回去找它的父类是系统加载器,系统加载器会根据classpath来查找所要加载的类,发现没有,接着由loader01去加载,loader01加载的时候找到文件执行接下操作,而LoaderTest01里主动使用了new LoaderTest02(), LoaderTest02也会执行上面同样的步骤, 但是LoaderTest01和LoaderTest02位于2个不同的加载器空间下,而他们之间是互相不可见的(他们的父子关系并不是继承,也有可能是组合,但是他们都是系统加载器的子类,对系统加载器里的资源都是共享的),所以在Loader01加载器加载的时候无法获取LoaderTest02
第三种情况:
运行结果如下:
分析:当执行load(loader02)的时候,会优先去找它的父加载器loader01, 而loader01又回去找它的父类是系统加载器,系统加载器会根据classpath来查找所要加载的类,并在当前目录下发现了这2个类,并执行操作,前2个加载器均为系统加载器,虽然lib1和lib2下2个文件在不同的类加载器空间下,但是实际执行并不需要它们,在系统一级已经执行完毕,而第三个,当执行load(loader03)的时候,父加载器null默认为根加载器,根加载器无法在相应的目录里找到相应的文件,于是交由其他加载器实现,而此时loader03加载器在相应的otherlib3下也无法找到相应的文件于是报错。
下一篇: String类内存解析
推荐阅读
-
通过实例解析js简易模块加载器
-
SpringMVC 自定义参数解析器.
-
java之jvm加载器例举
-
SpringBoot使用自定义json解析器的使用方法
-
Android图片加载框架解析之Glide的自定义模块功能讲解
-
C#_Excel数据读取与写入_自定义解析封装类_支持设置标题行位置&使用excel表达式收集数据&单元格映射&标题映射&模板文件的参数数据替换(第二版-增加深度读取和更新功能)
-
Spring boot中自定义Json参数解析器
-
Java语言中的自定义类加载器实例解析
-
别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】
-
JAVA-大白话探索JVM-类加载过程(二)