【发布时间】:2018-04-10 06:43:10
【问题描述】:
是否可以从 Pack200 创建的 pack.gz 文件中即时(在内存中)加载类,而无需先将其解压缩回 jar 中?我能找到的所有示例都向我展示了如何将其解压缩到 .jar 文件中,然后从 .jar 文件中加载类。
【问题讨论】:
-
是的,这通常使用 JWS 完成。
标签: java jar classloader
是否可以从 Pack200 创建的 pack.gz 文件中即时(在内存中)加载类,而无需先将其解压缩回 jar 中?我能找到的所有示例都向我展示了如何将其解压缩到 .jar 文件中,然后从 .jar 文件中加载类。
【问题讨论】:
标签: java jar classloader
是的,这是可能的。 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);
}
应该就足够了。但是,仍然存在两个问题:
finish() 之前关闭,从而导致 finish() 由于管道损坏而生成 IOException。为了解决第一个问题,我们可以重写 JarInputStream 的 close 方法来解决解包操作中的任何失败。要解决第二个问题,我们可以在 JarOutputStream 中覆盖 finish() 以不执行任何操作:
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;
}
}
};
}
【讨论】: