Jee*_*tha 2 java bouncycastle classpath classloader
我有一个项目使用两个版本的 bouncyCastle jars bcprov-jdk15 和 bcprov-jdk16。jvm 加载旧版本,但我编写的一个功能需要更新版本才能运行。我尝试使用自定义类加载器来解决这个类路径地狱。经过一番谷歌搜索并在以前的一些 Stackoverflow 答案[1] [2]和本博客的帮助下,我编写了以下Parent Last Class loader ,在委托给父类加载器之前从较新的 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我使用此类加载器加载了功能中的主类,但功能中使用的 BouncyCaslte 类并未由我的自定义类加载器加载。
ClassLoader loader = new ParentLastClassLoader(Thread.currentThread().getContextClassLoader(), pathToJar);
Class myClass = loader.loadClass("MainClassOfTheFeature");
Method mainMethod = myClass.getMethod("MainMethod");
mainMethod.invoke(myClass.getConstructor().newInstance());
Run Code Online (Sandbox Code Playgroud)
Jvm 仍然使用从旧版本加载的类。如何让 JVM 在运行该功能时从类加载器加载类,并在该功能未运行时使用旧 jar 中已加载的旧类?
编辑: 即使在功能主类的 MainMethod 中将自定义类加载器设置为线程上下文类加载器后,问题仍然存在。
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
Run Code Online (Sandbox Code Playgroud)
我设法解决了这个问题。修改ParentLastClassLoader的代码以获取该功能所需的所有 Jarfile 路径的数组。因此,当加载一个类时,将在该功能所需的所有 jar 文件中搜索 .class 文件。如果找不到类文件,它将委托给父级。
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
ParentLastClassLoader实例化如下。
ClassLoader loader = new ParentLastClassLoader(Thread.currentThread().getContextClassLoader(), paths);
Run Code Online (Sandbox Code Playgroud)
一旦 ParentLastClassLoader 被实例化,MainClassOfTheFeature将被加载并调用它的MainMethod 。
| 归档时间: |
|
| 查看次数: |
5359 次 |
| 最近记录: |