2016-02-27 64 views
1

我將整個.class文件(以及它的聲明類和匿名類)作爲byte []傳輸,希望能夠在另一個類上使用類加載器來定義它接收字節[]的計算機。加載自定義類加載器以加載java中傳輸的字節[]

我在Java: How to load Class stored as byte[] into the JVM?找到了一個解決方案,但是,我不明白如何使用這個ByteClassLoader用於我的目的。我只是張貼代碼在這裏再次:

public class ByteClassLoader extends URLClassLoader { 
private final Map<String, byte[]> extraClassDefs; 

public ByteClassLoader(URL[] urls, ClassLoader parent, Map<String, byte[]> extraClassDefs) { 
    super(urls, parent); 
    this.extraClassDefs = new HashMap<String, byte[]>(extraClassDefs); 
} 

@Override 
protected Class<?> findClass(final String name) throws ClassNotFoundException { 
    byte[] classBytes = this.extraClassDefs.remove(name); 
    if (classBytes != null) { 
     return defineClass(name, classBytes, 0, classBytes.length); 
    } 
    return super.findClass(name); 
} 

}

的問題是:我怎麼有實例嗎?

我試圖通過簡單地將它實例化爲ByteClassLoader b = new ByteClassLoader(...);但顯然,這是行不通的(如預期)。

我發現加載的程序開始一個新的類加載器的方式在https://analyzejava.wordpress.com/2014/09/25/java-classloader-loading-a-custom-classloader-on-jvm-start/使用-Djava.system.class.loader =...ByteClassLoader,但是,這並沒有工作,要麼(它沒有找到類ByteClassLoader。如果有人這將是對我很有幫助可以指向我如何使用引用的類加載器的正確方向(我對類加載器非常陌生,但尚未完全理解它們的工作方式)。反序列化()我實例化ByteClassLoader。因爲它沒有與引用的實現工作,我試圖做ByteClassLoader extends ClassLoader(我不知道從哪裏得到URL[]從),然後改變該線程的ContextClassLoader

public static Map<String, Class<?>> deserialize(Map<String, byte[]> classesToDefine) { 

    // SerializeUtils.class.getClassLoader(). 
    ByteClassLoader l = new ByteClassLoader(Thread.currentThread().getContextClassLoader(), classesToDefine); // TODO this 
                   // may be a 
                   // problem 
    Thread.currentThread().setContextClassLoader(l); 
    Map<String, Class<?>> classes = new HashMap<>(); 
    for (String className : classesToDefine.keySet()) { 
     try { 
      System.out.println("ClassName in deserialize: "+ className); 
      Class<?> c = ((ByteClassLoader)Thread.currentThread().getContextClassLoader()).findClass(className); 
      System.out.println("Class found is : " + c.getName()); 
      classes.put(className, c); 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } 
    } 
    return classes; 
} 

我希望實現的是,轉換後的字節數組現在可用於執行,使得我可以能夠實例化。我需要這個,因爲我也傳遞對象的實際數據使用序列化的字節數組和,之後我加載的類,將解碼該對象和使用使用它:

public static Object decodeJavaObject(byte[] me, int offset, int length) throws ClassNotFoundException, 
     IOException { 
    ByteArrayInputStream bais = new ByteArrayInputStream(me, offset, length); 
    ObjectInputStream ois = new ObjectInputStream(bais); 
    Object obj = ois.readObject(); 
    // no need to call close of flush since we use ByteArrayInputStream 
    return obj; 
} 

所以我打電話SerializeUtils。反序列化()以反序列化.class文件,希望之後可用。緊接着,我叫

所以完整的反序列化過程如下所示:

public static Job deserialize(JobTransferObject jobToDeserialize) throws ClassNotFoundException, IOException { 
    Job job = new Job(); 
    for (TransferObject taskTransferObject : jobToDeserialize.taskTransferObjects()) { 
     SerializeUtils.deserialize(taskTransferObject.classFiles()); 
     Task task = (Task) Utils.decodeJavaObject(taskTransferObject.data(), 0, taskTransferObject.data().length); 
     job.addTask(task); 
    } 

    return job; 
} 

所以我首先調用SerializeUtils.deserialize()反序列化具有希望的類文件,它們可用於下一調用Utils.decodeJavaObject,我試圖反序列化我傳遞的實際對象的字節[](所以我發送我想實例化的類的類文件,然後解碼我也通過網絡發送的那個類的對象)。 Task是反序列化的類文件擴展的抽象類,因此Task需要反序列化它的實現的程序)。順便說一句,TransferObject看起來像這樣:

public class TransferObject implements Serializable{ 
/** 
* 
*/ 
private static final long serialVersionUID = 8971732001157216939L; 
private byte[] data; 
private Map<String, byte[]> classFiles; 
private String className; 

public TransferObject(byte[] data, Map<String, byte[]> classFiles, String className) { 
    this.data = data; 
    this.classFiles = classFiles; 
    this.className = className; 
} 

public byte[] data() { 
    return this.data; 
} 

public Map<String, byte[]> classFiles() { 
    return this.classFiles; 
} 

public String className() { 
    return this.className; 
} 

}

(數據=另一臺計算機,類文件=該擴展對象的序列的類文件,以及類名上延伸任務擴展的類的實際名稱序列化對象)

另一臺計算機上的任務擴展看起來像例如像這樣:

Task initShutdown = new Task(writeTask.currentId(), NumberUtils.next()) { 

     /** 
     * 
     */ 
     private static final long serialVersionUID = -5543401293112052880L; 

     @Override 
     public void broadcastReceiver(NavigableMap<Number640, Data> input, DHTConnectionProvider dht) 
       throws Exception { 
      dht.shutdown(); 
     } 

    }; 

,任務抽象類只是下面的代碼:

public abstract class Task implements Serializable { 

/** 
* 
*/ 
private static final long serialVersionUID = 9198452155865807410L; 
private final Number640 previousId; 
private final Number640 currentId; 

public Task(Number640 previousId, Number640 currentId) { 
    this.previousId = previousId; 
    this.currentId = currentId; 
} 

public abstract void broadcastReceiver(NavigableMap<Number640, Data> input, DHTConnectionProvider dht) 
     throws Exception; 


public Number640 currentId() { 
    return this.currentId; 
} 

public Number640 previousId() { 
    return this.previousId; 
}} 

很抱歉的複雜的解釋...

+0

「但很明顯,這是不工作」=>爲什麼呢?如果你這樣做會發生什麼?你究竟做得如何? – Seelenvirtuose

+0

我添加了一些代碼來顯示我如何使用它。 – Ollyblink

+0

我忘了:Utils.decodeJavaObject方法中的Object obj = ois.readObject()會導致該類的「ClassNotFound」異常被反序列化,儘管在解碼工作之前解序列化正好。 – Ollyblink

回答

0

,而不必測試了,這裏是我的建議:

創建定義每個地圖的單一類加載器:

public static Job deserialize(JobTransferObject jobToDeserialize) throws ClassNotFoundException, IOException { 
    Job job = new Job(); 
    for (TransferObject taskTransferObject : jobToDeserialize.taskTransferObjects()) { 
     ClassLoader cl = new ByteClassLoader(new URL[0], Task.class.getClassLoader(), taskTransferObject.classFiles()); 
     Task task = (Task)Utils.decodeJavaObject(taskTransferObject.data(), 0, taskTransferObject.data().length, cl); 
     job.addTask(task); 
    } 
    return job; 
} 

,並延長ObjectInputStream使用這個類加載器在反序列化:

public static Object decodeJavaObject(byte[] me, int offset, int length, final ClassLoader cl) throws ClassNotFoundException, IOException { 
    ByteArrayInputStream bais = new ByteArrayInputStream(me, offset, length); 
    ObjectInputStream ois = new ObjectInputStream(bais) { 
     @Override 
     protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) 
       throws IOException, ClassNotFoundException { 

      Class<?> clazz = Class.forName(objectStreamClass.getName(), false, cl); 
      if (clazz != null) { 
       return clazz; 
      } else { 
       return super.resolveClass(objectStreamClass); 
      } 
     } 

     @Override 
     protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { 
      Class<?>[] interfaceClasses = new Class[interfaces.length]; 
      for (int i = 0; i < interfaces.length; i++) { 
       interfaceClasses[i] = Class.forName(interfaces[i], false, cl); 
      } 
      try { 
       return Proxy.getProxyClass(cl, interfaceClasses); 
      } catch (IllegalArgumentException e) { 
       return super.resolveProxyClass(interfaces); 
      } 
     } 
    }; 
    Object obj = ois.readObject(); 
    return obj; 
}