如果在同一个JVM中使用不同jar包下面包名和类名完全相同的类

背景:在引入第三方jar包以后,偶尔会遇到不同jar包中的类冲突。这里所说的冲突,是指类的包名和类型完全相同(有的时候希望同时使用相同类的不同版本)。

参考地址:https://baijiahao.baidu.com/s?id=1636309817155065432&wfr=spider&for=pc

处理思路:见上图,使用原生的类加载是实现不了这个功能的,需要使用自定义类加载器,分别从不同jar中或者目录加载class文件,然后进行实例化,最后使用反射来调用(因Class动态变化,所以需要反射机制)

代码实现:

package com.mp.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class MyClassloader extends ClassLoader {

  private String libPath;

  public MyClassloader(String path) {
    libPath = path;
  }

  @Override
  public Class<?> findClass(String name) throws ClassNotFoundException {
    if (libPath.endsWith(".zip") || libPath.endsWith(".jar")) {
      try {
        return this.loadClassFromJarOrZip(name);
      } catch (MalformedURLException e) {
        e.printStackTrace();
      }
    }
    String fileName = getFileName(name);
    File file = new File(libPath, fileName);
    try (FileInputStream is = new FileInputStream(file);
        ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
      int len = 0;
      while ((len = is.read()) != -1) {
        bos.write(len);
      }
      byte[] data = bos.toByteArray();
      return defineClass(name, data, 0, data.length);
    } catch (IOException e) {
      e.printStackTrace();
    }
    return super.findClass(name);
  }

  // 获取要加载 的class文件名
  private String getFileName(String name) {
    int index = name.lastIndexOf(".");
    if (index > 0) {
      return name.substring(index + 1) + ".class";
    } else {
      return name + ".class";
    }
  }

  private Class<?> loadClassFromJarOrZip(String className)
      throws MalformedURLException, ClassNotFoundException {
    File file = new File(libPath);
    URL url = file.toURI().toURL();
    URLClassLoader classLoader = null;
    try {
      classLoader =
          new URLClassLoader(new URL[] {url}, Thread.currentThread().getContextClassLoader());
      return classLoader.loadClass(className);
    } finally {
      if (classLoader != null) {
        try {
          classLoader.close();
        } catch (IOException e) {
          // pass
        }
      }
    }
  }
}
package com.mp.util;

import java.lang.reflect.Method;

public class ClassLoaderTest {
  public static void main(String[] args) throws ClassNotFoundException {
    System.out.println("使用目录加载class");
    call("/tmp/t1", "basic.javastd.HelloWorld", "printVersion");
    call("/tmp/t2", "basic.javastd.HelloWorld", "printVersion");
    System.out.println("使用jar加载class");
    call("/tmp/t1/javastd-0.0.1-SNAPSHOT.jar", "basic.javastd.HelloWorld", "printVersion");
    call("/tmp/t2/javastd-0.0.1-SNAPSHOT.jar", "basic.javastd.HelloWorld", "printVersion");
  }

  public static void call(String classFilePath, String className, String methodName) {
    ClassLoader loader = new MyClassloader(classFilePath);
    try {
      Class<?> loadClass = loader.loadClass(className);
      Method declaredMethod = loadClass.getDeclaredMethod(methodName);
      declaredMethod.invoke(loadClass.newInstance());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

输出:

使用目录加载class

v1 static code

version 1

v2 static code

version 2

使用jar加载class

v1 static code

version 1

v2 static code

version 2

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值