1. 自定义 classloader
有时候,我们在项目开发的时候,会遇到比较恶心的问题,存在两个不同 jar 包,但是类的全限定名是一样的,而这两个包都不能删除,这时候调用可能就会出问题。
如何解决上面的问题? 我的答案就是自定义类加载器。
场景模拟
module-a: 表示 a.jarmodule-b: 表示 b.jarmodule-main: 表示 程序入口
由于在 module-main 项目中同时引入了 module-a 和 module-b 这两个 jar 包,但是存在冲突类 HelloService, 最终导致程序运行错误。
如何自定义 classloader,来解决问题?
- 重新定义 
loadClass 方法,打破父类委托机制 - 使用 
getResources 方法来获取所有的 class 文件,然后判断 
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  |   @SneakyThrows
  public String test1(String message) {
    // 查找类
    ClassLoader classLoader = new ModuleAClassLoader();
    Class<?> clazz = classLoader.loadClass("com.ooooo.HelloService");
    // 执行
    Method test1 = ReflectionUtils.findMethod(clazz, "test1", String.class);
    Object result = test1.invoke(null, message);
    return (String) result;
  }
  @SneakyThrows
  public String test2(String message) {
    // 查找类
    ClassLoader classLoader = new ModuleBClassLoader();
    Class<?> clazz = classLoader.loadClass("com.ooooo.HelloService");
    // 执行
    Method test2 = ReflectionUtils.findMethod(clazz, "test2", String.class);
    Object result = test2.invoke(null, message);
    return (String) result;
  }
  private static class ModuleAClassLoader extends ClassLoader {
    public ModuleAClassLoader() {
      super(ModuleAClassLoader.class.getClassLoader());
    }
    @SneakyThrows
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
      Class<?> c = findLoadedClass(name);
      if (c == null) {
        // 当前路径下去找
        if (name.contains("com.ooooo")) {
          String path = name.replace(".", "/") + ".class";
          Enumeration<URL> resources = getResources(path);
          URL targetUrl = null;
          while (resources.hasMoreElements()) {
            targetUrl = resources.nextElement();
            if (targetUrl.toString().contains("module-a")) {
              break;
            }
          }
          // 读取 class 文件
          InputStream in = targetUrl.openStream();
          byte[] bytes = StreamUtils.copyToByteArray(in);
          in.close();
          c = defineClass(name, bytes, 0, bytes.length);
        }
      }
      if (c == null) {
        c = getParent().loadClass(name);
      }
      if (resolve) {
        resolveClass(c);
      }
      return c;
    }
  }
  private static class ModuleBClassLoader extends ClassLoader {
    public ModuleBClassLoader() {
      super(ModuleAClassLoader.class.getClassLoader());
    }
    @SneakyThrows
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
      Class<?> c = findLoadedClass(name);
      if (c == null) {
        // 当前路径下去找
        if (name.contains("com.ooooo")) {
          String path = name.replace(".", "/") + ".class";
          Enumeration<URL> resources = getResources(path);
          URL targetUrl = null;
          while (resources.hasMoreElements()) {
            targetUrl = resources.nextElement();
            if (targetUrl.toString().contains("module-b")) {
              break;
            }
          }
          // 读取 class 文件
          InputStream in = targetUrl.openStream();
          byte[] bytes = StreamUtils.copyToByteArray(in);
          in.close();
          c = defineClass(name, bytes, 0, bytes.length);
        }
      }
      if (c == null) {
        c = getParent().loadClass(name);
      }
      if (resolve) {
        resolveClass(c);
      }
      return c;
    }
  }
}
  | 
2. 代码实现位置
github 地址