2013-07-21 65 views
2

我有一個使用bouncyCastle jars bcprov-jdk15和bcprov-jdk16兩個版本的項目。 jvm加載舊版本,但是我寫了一個需要更新版本運行的功能。我試圖通過使用自定義類加載器來解決這個類路徑。經過一些谷歌搜索和一些以前的Stackoverflow答案[1][2]blog,我寫了以下代碼Parent Last Class loader在委託給父類加載器之前從較新的jar加載類。父上次Classloader解決Java Class path hell?

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線程上下文ClassLoader之後。

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

回答

4

我設法解決了這個問題。修改了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); 
     } 
    } 
} 

ParentLastClassLoader如下被實例化。

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

一旦ParentLastClassLoader被實例化,所述MainClassOfTheFeature將被加載和其MainMethod將被調用。

+0

我還沒有完全理解它是如何工作的或者它爲什麼需要,但這是目前我能夠自動鏈接我的jar中的其他類的唯一方法。 – Benjoyo

1

好的,你創建了你自己的類加載器,然後使用它加載一個類。問題是 - 線程類加載器如何知道這個問題? 所以,你必須使用一些類加載器加載類,然後將此類加載器設置爲線程上下文類加載器。

+0

感謝您的回答。請參閱編輯。 – Jeewantha