gpt4 book ai didi

java - Parent Last Classloader解决Java Class路径 hell ?

转载 作者:行者123 更新时间:2023-11-30 06:23:49 24 4
gpt4 key购买 nike

我有一个项目使用两个版本的 bouncyCaSTLe jar bcprov-jdk15 和 bcprov-jdk16。 jvm 加载旧版本,但我编写的功能需要更新版本才能运行。我试图通过使用自定义类加载器来解决这个类路径 hell 。经过一些谷歌搜索并借助以前的一些 Stackoverflow 答案 [1] [2]还有这个blog ,我编写了以下 Parent Last Class loader 以在委托(delegate)给父类加载器之前从较新的 jar 加载类。

public class ParentLastClassLoader extends ClassLoader {

private String jarFile; //Path to the jar file
private Hashtable classes = new Hashtable(); //used to cache already defined classes

public ParentLastClassLoader(ClassLoader parent, String path)
{
super(parent);
this.jarFile = path;
}

@Override
public Class<?> findClass(String name) throws ClassNotFoundException
{
System.out.println("Trying to find");
throw new ClassNotFoundException();
}

@Override
protected synchronized Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException
{
System.out.println("Trying to load");
try
{
System.out.println("Loading class in Child : " + className);
byte classByte[];
Class result = null;

//checks in cached classes
result = (Class) classes.get(className);
if (result != null) {
return result;
}

try {
JarFile jar = new JarFile(jarFile);
JarEntry entry = jar.getJarEntry(className + ".class");
InputStream is = jar.getInputStream(entry);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int nextValue = is.read();
while (-1 != nextValue) {
byteStream.write(nextValue);
nextValue = is.read();
}

classByte = byteStream.toByteArray();
result = defineClass(className, classByte, 0, classByte.length, null);
classes.put(className, result);
return result;
} catch (Exception e) {
throw new ClassNotFoundException(className + "Not found", e);
}
}
catch( ClassNotFoundException e ){

System.out.println("Delegating to parent : " + className);
// didn't find it, try the parent
return super.loadClass(className, resolve);
}
}
}

我使用此类加载器加载了功能中的主类,但我的自定义类加载器未加载功能中使用的 BouncyCaslte 类。

ClassLoader loader = new ParentLastClassLoader(Thread.currentThread().getContextClassLoader(), pathToJar);
Class myClass = loader.loadClass("MainClassOfTheFeature");
Method mainMethod = myClass.getMethod("MainMethod");
mainMethod.invoke(myClass.getConstructor().newInstance());

Jvm 仍然使用它从旧版本加载的类。如何让 JVM 在运行该功能时从我的类加载器加载类,并在该功能未运行时使用旧 jar 中已加载的旧类?

编辑:即使在功能主类的 MainMethod 中将自定义类加载器设置为线程上下文类加载器后,问题仍然存在。

Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());

最佳答案

我设法解决了这个问题。修改了 ParentLastClassLoader 的代码以获取功能所需的所有 Jarfile 路径 的数组。因此,当加载一个类时,将在该功能所需的所有 jar 文件中搜索 .class 文件。如果找不到类文件,它将委托(delegate)给父级。

    private  class ParentLastClassLoader extends ClassLoader {

private String[] jarFiles; //Paths to the jar files
private Hashtable classes = new Hashtable(); //used to cache already defined classes

public ParentLastClassLoader(ClassLoader parent, String[] paths)
{
super(parent);
this.jarFiles = paths;
}

@Override
public Class<?> findClass(String name) throws ClassNotFoundException
{
System.out.println("Trying to find");
throw new ClassNotFoundException();
}

@Override
protected synchronized Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException
{
System.out.println("Trying to load");
try
{
System.out.println("Loading class in Child : " + className);
byte classByte[];
Class result = null;

//checks in cached classes
result = (Class) classes.get(className);
if (result != null) {
return result;
}

for(String jarFile: jarFiles){
try {
JarFile jar = new JarFile(jarFile);
JarEntry entry = jar.getJarEntry(className.replace(".","/") + ".class");
InputStream is = jar.getInputStream(entry);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int nextValue = is.read();
while (-1 != nextValue) {
byteStream.write(nextValue);
nextValue = is.read();
}

classByte = byteStream.toByteArray();
result = defineClass(className, classByte, 0, classByte.length, null);
classes.put(className, result);
} catch (Exception e) {
continue;
}
}

result = (Class) classes.get(className);
if (result != null) {
return result;
}
else{
throw new ClassNotFoundException("Not found "+ className);
}
}
catch( ClassNotFoundException e ){

System.out.println("Delegating to parent : " + className);
// didn't find it, try the parent
return super.loadClass(className, resolve);
}
}
}

ParentLastClassLoader 实例化如下。

ClassLoader loader = new ParentLastClassLoader(Thread.currentThread().getContextClassLoader(), paths);

ParentLastClassLoader 实例化后,将加载 MainClassOfTheFeature 并调用其 MainMethod

关于java - Parent Last Classloader解决Java Class路径 hell ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17775591/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com