自定义类加载器
Java日常开发过程中,类的加载几乎是由引导类加载器和系统类加载器配合执行,在必要的时候我们还可以自定义类加载器。
为什么要自定义类加载器
- 隔离加载类
- 修改类加载的方式
- 扩展加载源
- 防止源码泄露
如何实现自定义类加载器
- 通过继承抽象类java.lang.Classloader ,实现自己的类加载器,满足一些特殊需求
- 在JDK1.2之前,在自定义类加载器的时候,总会去继承CLassLoader类并重写loadClass()方法,从而实现自定义类的加载;JDK1.2之后已经不建议重写loadClass()方法,而是建议把自定义的类加载逻辑写在findClass()方法中
- 在编写自定义类加载器时,没有太过复杂的需求可以直接继承URLClassLoader类,这样就可以避免自己去编写findClass()方法以及获取字节码流的方式,使自定义类加载器的编写更加简洁
1 package jvm.classload; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.File; 5 import java.io.FileInputStream; 6 import java.io.IOException; 7 import java.io.InputStream; 8 9 /** 10 * 自定义类加载器 11 * 12 * @Author: cunxiaopan 13 * @Date: 2020/09/04 14:37 14 * @Description: 实现从某个文件读取字节流,加载该类的功能 15 */ 16 public class CustomClassLoader extends ClassLoader { 17 18 private String path; 19 20 public CustomClassLoader(String path) { 21 this.path = path; 22 } 23 24 @Override 25 protected Class<?> findClass(String name) throws ClassNotFoundException { 26 try { 27 byte[] bytes = getClassFromCustomPath(name); 28 return defineClass(name, bytes, 0, bytes.length); 29 } catch (IOException e) { 30 e.printStackTrace(); 31 } 32 return super.findClass(name); 33 } 34 35 private byte[] getClassFromCustomPath(String name) throws IOException { 36 // 从自定义路径中加载指定类 37 //如果指定路径的字节码文件进行了加密,则需要在此方法中解密 38 String fileName = name.replace(".", "/"); 39 fileName = path + fileName + ".class"; 40 InputStream is = null; 41 ByteArrayOutputStream outputStream = null; 42 try { 43 is = new FileInputStream(new File(fileName)); 44 outputStream = new ByteArrayOutputStream(); 45 int i = 0; 46 while ((i = is.read()) != -1) { 47 outputStream.write(i); 48 } 49 } catch (Exception e) { 50 e.printStackTrace(); 51 } finally { 52 if (outputStream != null) { 53 outputStream.close(); 54 } 55 if (is != null) { 56 is.close(); 57 } 58 } 59 return outputStream.toByteArray(); 60 } 61 62 public static void main(String[] args) { 63 // class 文件位置 目录 /Users/xiao/projects/jvm/other/Hello.class 64 String path = System.getProperty("user.dir") + "/other/"; 65 System.out.println(path); 66 CustomClassLoader customClassLoader = new CustomClassLoader(path); 67 try { 68 String name = "Hello"; 69 70 Class<?> clazz2 = customClassLoader.loadClass(name); 71 Object obj2 = clazz2.newInstance(); 72 System.out.println(obj2.getClass().getClassLoader()); 73 74 Class<?> clazz = Class.forName(name, true, customClassLoader); 75 Object obj = clazz.newInstance(); 76 System.out.println(obj.getClass().getClassLoader()); 77 78 /*for (int i = 0; i < clazz.getMethods().length; i++) { 79 System.out.println(clazz.getMethods()[i].getName()); 80 } 81 System.out.println("=========================="); 82 for (int i = 0; i < clazz.getDeclaredMethods().length; i++) { 83 System.out.println(clazz.getDeclaredMethods()[i].getName()); 84 }*/ 85 } catch (ClassNotFoundException e) { 86 e.printStackTrace(); 87 } catch (IllegalAccessException e) { 88 e.printStackTrace(); 89 } catch (InstantiationException e) { 90 e.printStackTrace(); 91 } 92 } 93 94 }
完整代码在github上进行记录