jvm的传唱-类加载
PS:承接上一篇文档,由于初次写文档记录类内容,对于博客园目前的文档编译不熟悉,第一篇文章写的太不好看了,这次换了个模式 ,看看能好看点不,便于阅读。
先通过代码看看类加载器的种类和效果
1 package com.bface.calculate; 2 3 /** 4 * @ClassName ClassLoaderLecode 5 * @Description TODO 6 * @Author cy 7 * @Date 2021/7/20 14:26 8 * @Version 1.0 9 */ 10 public class ClassLoaderLecode { 11 public static void main(String[] args) { 12 //获取系统类加载器--> 它负责加载环境变量classpath或系统属性java.class.path 指定路径下的类 13 //库 14 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); 15 System.out.println("系统类加载器"+ systemClassLoader); 16 //获取扩展类加载器-->由sun.misc.Launcher$ExtClassLoader实现 2、从java.ext.dirs系统属性所指定的目录中加载类库, 17 //或从JDK的安装目录的jre/lib/ext 子目录(扩展目录)下加载类库 18 ClassLoader parent = systemClassLoader.getParent(); 19 System.out.println("扩展类加载器"+parent); 20 //启动类加载器-->这个类加载器使用c/c++实现,嵌套再jvm内部 2、它用来加载Java的核心类库(JAVA_HOME/jre/lib/rt.jar、 resource.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类 21 ClassLoader parent1 = parent.getParent(); 22 System.out.println("启动类加载器"+parent1); 23 24 //获取用户自定的类的类默认类加载器 25 ClassLoader classLoader = ClassLoaderLecode.class.getClassLoader(); 26 System.out.println("自定义类的类加载器"+classLoader); 27 } 28 29 }
为什么要使用这种模式呢,这里简单说两句,1.保障同一个类型 尤其是底层库类的唯一性,防止非法篡改,在jvm中判断一个对象的类型是与类加载器有关的,不同的类加载器即便对于开发人员来说一样的对象代码,表示出来的类型也是不一样的,所以还是能区别出来。
如何实现自定义的类加载器呢,每次通过先委托父类加载器加载,当父类加载器无法加载时,再自己加载。其实 ClassLoader 类默认的 loadClass 方法已经帮我们写好了,我们无需去写。
有的小伙伴可能会疑问,为什么要自定义类加载器,平时开发好像没怎么用到,有啥用呢?我总结自己觉得可能用到的地方,有的地方写的第三方jar包需要给别人使用,为了保障代码相对安全不被轻易解读,可以通过自定义类加载器在加载时进行加密处理,这样相对来说吧 是能解决安全问题的。
开始编写自定义类加载器代码如下,大家可以参考借鉴
1 package com.bface.calculate; 2 3 import javax.jnlp.ExtendedService; 4 import java.io.BufferedInputStream; 5 import java.io.ByteArrayOutputStream; 6 import java.io.FileInputStream; 7 import java.io.IOException; 8 import java.util.Calendar; 9 10 /** 11 * @ClassName ClassLoaderLecode 12 * @Description TODO 13 * @Author cy 14 * @Date 2021/7/20 14:26 15 * @Version 1.0 16 */ 17 public class ClassLoaderLecode { 18 public static void main(String[] args) { 19 //获取系统类加载器--> 它负责加载环境变量classpath或系统属性java.class.path 指定路径下的类 20 //库 21 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); 22 System.out.println("系统类加载器" + systemClassLoader); 23 //获取扩展类加载器-->由sun.misc.Launcher$ExtClassLoader实现 2、从java.ext.dirs系统属性所指定的目录中加载类库, 24 //或从JDK的安装目录的jre/lib/ext 子目录(扩展目录)下加载类库 25 ClassLoader parent = systemClassLoader.getParent(); 26 System.out.println("扩展类加载器" + parent); 27 //启动类加载器-->这个类加载器使用c/c++实现,嵌套再jvm内部 2、它用来加载Java的核心类库(JAVA_HOME/jre/lib/rt.jar、 resource.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类 28 ClassLoader parent1 = parent.getParent(); 29 System.out.println("启动类加载器" + parent1); 30 31 //获取用户自定的类的类默认类加载器 32 ClassLoader classLoader = ClassLoaderLecode.class.getClassLoader(); 33 System.out.println("自定义类的类加载器" + classLoader); 34 35 36 ClassLoaderLecode classLoaderLecode = new ClassLoaderLecode(); 37 try { 38 ZdyClassLoader zdyClassLoader = classLoaderLecode.new ZdyClassLoader("D:\\IdeaProjects\\leecode\\out\\production\\leecode\\com\\bface\\calculate\\"); 39 Class<?> arrayLecode = zdyClassLoader.loadClass("ArrayLecode"); 40 System.out.println("我是由" + arrayLecode.getClassLoader().getClass().getName() + "类加载器加载的"); 41 42 } catch (ClassNotFoundException e) { 43 e.printStackTrace(); 44 } 45 } 46 47 class ZdyClassLoader extends ClassLoader { 48 private String codePath; 49 50 public ZdyClassLoader(ClassLoader parent, String codePath) { 51 52 } 53 54 public ZdyClassLoader(String codePath) { 55 this.codePath = codePath; 56 57 } 58 59 @Override 60 protected Class<?> findClass(String name) throws ClassNotFoundException { 61 BufferedInputStream bis = null; 62 ByteArrayOutputStream baos = null; 63 try { 64 65 //1.字节码路径 66 String fileName = codePath + name + ".class"; 67 //2.获取输入流 68 bis = new BufferedInputStream(new FileInputStream(fileName)); 69 //3.获取输出流 70 baos = new ByteArrayOutputStream(); 71 //4.io读写 72 73 int len; 74 byte[] data = new byte[1024]; 75 while ((len = bis.read(data)) != -1) { 76 baos.write(data, 0, len); 77 } 78 //5.获取内存中字节数组 79 byte[] byteCode = baos.toByteArray(); 80 //6.调用defineClass 将字节数组转成Class对象 81 Class<?> defineClass = defineClass(null, byteCode, 0, byteCode.length); 82 return defineClass; 83 } catch (IOException e) { 84 e.printStackTrace(); 85 } finally { 86 try { 87 if (bis != null) { 88 bis.close(); 89 } 90 if (baos != null) { 91 baos.close(); 92 } 93 } catch (IOException e) { 94 e.printStackTrace(); 95 } 96 } 97 return null; 98 } 99 } 100 101 }
"C:\Program Files\Java\jdk1.8.0_66\bin\java.exe" -Dvisualvm.id=603520010088200 "-javaagent:D:\ProgramSoft\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=63737:D:\ProgramSoft\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_66\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\rt.jar;D:\IdeaProjects\leecode\out\production\leecode" com.bface.calculate.ClassLoaderLecode
系统类加载器sun.misc.Launcher$AppClassLoader@14dad5dc
扩展类加载器sun.misc.Launcher$ExtClassLoader@1b6d3586
启动类加载器null
自定义类的类加载器sun.misc.Launcher$AppClassLoader@14dad5dc
我是由com.bface.calculate.ClassLoaderLecode$ZdyClassLoader类加载器加载的