自定义类加载器

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上进行记录

posted @ 2020-09-04 18:28  衰草寒烟  阅读(309)  评论(0编辑  收藏  举报