2017-10-29 4 views
0

Pack200에 의해 생성 된 pack.gz 파일에서 (메모리에) 클래스를 처음으로 병에 압축을 풀지 않고도로드 할 수 있습니까? 모든 예제는 .jar 파일로 압축을 풀고 .jar 파일에서 클래스를로드하는 방법을 보여줍니다.포장을 풀지 않고도 Pack200 파일을 사용할 수 있습니까?

+0

, 이것은 일상적으로 JWS 이루어집니다 : 두 번째를 해결하기 위해, 우리는 아무것도하지 않고하는 JarOutputStream에 finish()을 대체 할 수 있습니다. – EJP

답변

0

예, 가능합니다. Pack200.Unpacker.unpack 메서드는 JarOutputStream에 기록합니다. 백그라운드 스레드에서이 작업을 수행하면 새 JarOutputStream을 파이프를 사용하여 JarInputStream에 연결하고이를 통해 읽을 수 있습니다.

public JarInputStream readPackFile(Path packGzFile) 
throws IOException { 

    PipedInputStream pipeIn = new PipedInputStream(); 
    PipedOutputStream pipeOut = new PipedOutputStream(pipeIn); 

    ExecutorService executor = Executors.newSingleThreadExecutor(); 
    Callable<Void> unpacker = new Callable<Void>() { 
     @Override 
     public Void call() 
     throws IOException { 
      try (InputStream file = 
        new GZIPInputStream(
         new BufferedInputStream(
          Files.newInputStream(packGzFile))); 
       JarOutputStream jarOutput = new JarOutputStream(pipeOut)) { 

       Pack200.newUnpacker().unpack(file, jarOutput); 
       return null; 
      } finally { 
       executor.shutdown(); 
      } 
     } 
    }; 
    executor.submit(unpacker); 

    return new JarInputStream(pipeIn); 
} 

충분한되어야한다. 그러나 여전히 두 가지 문제가 있습니다.

  • 압축 풀기 작업에 오류가있는 경우 ExecutorServices가 해당 작업의 예외를 억제하기 때문에 절대로 알 수 없습니다.
  • JarInputStream 및 JarOutputStream (특히, 수퍼 클래스, InflaterInputStream 및 DeflaterOutputStream)이 파이프와 제대로 작동하지 않습니다. JarOutputStream를 닫으면 finish() 메서드로 강제 호출되지만 파이프의 다른쪽에있는 JarInputStream이 해당 데이터를 읽지 않기 때문입니다. 즉, finish()가 불려 가기 전에 JarInputStream가 거의 확실히 닫혀 버려, 깨진 파이프에 의해 finish()에 IOException가 생성되는 것을 의미합니다.

우리가 압축 풀기 운영중인 고장을 고려하여 JarInputStream의 close 방법을 대체 할 수 있습니다, 첫 번째 문제를 해결하려면. 예

public JarInputStream readPackFile(Path packGzFile) 
throws IOException { 

    PipedInputStream pipeIn = new PipedInputStream(); 
    PipedOutputStream pipeOut = new PipedOutputStream(pipeIn); 

    class NonFinishingJarOutputStream 
    extends JarOutputStream { 
     NonFinishingJarOutputStream(OutputStream out) 
     throws IOException { 
      super(out); 
     } 

     @Override 
     public void finish() 
     throws IOException { 
      // Deliberately empty. 
     } 
    } 

    ExecutorService executor = Executors.newSingleThreadExecutor(); 
    Callable<Void> unpacker = new Callable<Void>() { 
     @Override 
     public Void call() 
     throws IOException { 
      try (InputStream file = 
        new GZIPInputStream(
         new BufferedInputStream(
          Files.newInputStream(packGzFile))); 
       JarOutputStream jarOutput = 
        new NonFinishingJarOutputStream(pipeOut)) { 

       Pack200.newUnpacker().unpack(file, jarOutput); 
       return null; 
      } finally { 
       executor.shutdown(); 
      } 
     } 
    }; 
    Future<?> unpackerTask = executor.submit(unpacker); 

    return new JarInputStream(pipeIn) { 
     @Override 
     public void close() 
     throws IOException { 
      super.close(); 
      try { 
       // If the unpack generated an exception, propagate it here. 
       unpackerTask.get(); 
      } catch (ExecutionException e) { 
       throw new IOException(e); 
      } catch (InterruptedException e) { 
       InterruptedIOException iie = new InterruptedIOException(); 
       iie.initCause(e); 
       throw iie; 
      } 
     } 
    }; 
} 
+0

JarFile이 아니라 JarInputStream을 제공합니다. https://stackoverflow.com/questions/16602668/creating-a-classloader-to-load-a-jar-file-from-a-byte-array는 실제로 JarInputStream을 사용하여 실제로 많은 작업을 수행하는 것이 어렵다는 것을 나타내는 것 같습니다. . –

+1

모든 JarFile 생성자에는 파일이 필요합니다. 나는 JarFile 클래스를 사용하지 않는 방법이 없다고 확신한다. – VGR