Родительский последний classloader, чтобы решить путь Java-класс, черт возьми?



У меня есть проект, который использует две версии после установки BouncyCastle банки bcprov-jdk15 и bcprov-jdk16. Jvm загружает старую версию, но есть функция, которую я написал, для запуска которой требуется более новая версия. Я попытался решить эту проблему с помощью пользовательского загрузчика классов. После некоторого гугления и с помощью некоторых предыдущих ответов Stackoverflow[1] [2] и этот блог, я написал следующий Родительский загрузчик последнего класса, чтобы загрузить классы из более новых банку, прежде чем делегировать, чтобы загрузчик родительского класса.



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());
622   2  

2 ответов:

Мне удалось решить эту проблему. Модифицировал код ParentLastClassLoader, чтобы получить массив всех путей Jarfile, которые необходимы функции. Поэтому, когда класс загружен, все jarfiles, необходимые для функции, будут найдены .файл класса. Если файл класса не может быть найден, он будет делегирован родительскому файлу.

    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 .

Ок, вы создали свой собственный загрузчик классов, а затем загрузили класс с его помощью. Вопрос в том, как загрузчик классов потока узнает об этом? Таким образом, вы должны загрузить класс с помощью некоторого загрузчика классов, а затем установить этот загрузчик классов в качестве загрузчика контекста потока.

Comments

    Ничего не найдено.