2015-03-10 3 views
3

Я хочу загрузить JAR динамически, прямо для памяти.
Скажем, у меня есть буфер, содержащий JAR, и я хочу загрузить все классы внутри JAR или, по крайней мере, перечислить все файлы, которые существуют внутри JAR. (классы, изображения и т. д.).
Что делать, если первый класс, который я загружаю, зависит, например, от второго класса? Знает ли java, как с этим справиться? Или я сам позабочусь об этом?Загрузка JAR динамически из памяти

+0

http://stackoverflow.com/questions/ 60764/how-should-i-load-jars-dynamic-at-runtime – Maksym

+0

@Maksym Это не отвечает на мой вопрос, так как я спросил, как делать это прямо из памяти, а не из пути. –

+0

Не имеет значения, где он находится ... – Maksym

ответ

0

Вы должны использовать пользовательский ClassLoader и установить JAR-файл в его путь к классам.

Классы всегда загружаются лениво, вы явно не загружаете их. Когда JAR находится на пути класса ClassLoader, вы можете разрешать ресурсы.

+0

Поскольку я хочу загрузить классы внутри JAR прямо из памяти, я думаю, что я не могу установить JAR в пути к классам. Или я ошибаюсь? –

+0

Что вы подразумеваете под «Поскольку я хочу загрузить классы внутри JAR прямо из памяти»? Являются ли они в JAR или в памяти? – Crazyjavahacking

+0

В памяти есть буфер, структура которого похожа на файл JAR. –

1

Вы, возможно, придется написать банку на диск, а затем вы можете использовать следующее, чтобы добавить его к классам: (full answer here)

URLClassLoader child = new URLClassLoader (myJar.toURL(), this.getClass().getClassLoader()); 
Class classToLoad = Class.forName ("com.MyClass", true, child); 
Method method = classToLoad.getDeclaredMethod ("myMethod"); 
Object instance = classToLoad.newInstance(); 
Object result = method.invoke (instance); 

Если вы хотите перечислить содержимое кувшина, который не является в пути к классам, вы всегда можете рассматривать его как почтовый файл: (see full answer here)

ZipFile zipFile = new ZipFile("testfile.zip"); 
Enumeration zipEntries = zipFile.entries(); 
String fname; 
while (zipEntries.hasMoreElements()) { 
    fname = ((ZipEntry)zipEntries.nextElement()).getName(); 
} 
0

Здесь вы можете использовать URLClassLoader, чтобы загрузить банку. см. В примере. У меня есть jar, который имеет класс с именем com.x.Test и имеет метод печати. ​​Ниже приведено описание способа загрузки класса и вызова метода. Это просто пример, но лучше использовать интерфейсы, фабричные методы и отражение может сделать этот код лучше,

File jarFile = new File("myspace\\my.jar"); 
URLClassLoader loader = new URLClassLoader(new URL[]{jarFile.toURL()}); 
Class<?> clazz = loader.loadClass("com.x.Test"); 
clazz.getMethod("print").invoke(clazz.getConstructor().newInstance(), args); 
+0

Он загружает JAR с диска, а не из памяти. –

4

Поскольку вы сказали, «по крайней мере, список всех файлов, которые существуют внутри JAR», давайте начнем с этой довольно простой задачей.

Предположим, у вас есть JarFile в массив байтов, byte[] buffer:

try(JarInputStream is=new JarInputStream(new ByteArrayInputStream(buffer))) { 
    for(;;) { 
     JarEntry nextEntry = is.getNextJarEntry(); 
     if(nextEntry==null) break; 
     System.out.println(nextEntry); 
    } 
} 

Загрузка классов из такого представления не работает вне коробки, так как стандартные ClassLoader реализации полагаются на JarFile реализация, которая опирается на физический файл, а не на абстракцию.

Так что, если вы просто не запишете буфер во временный файл, это сводится к реализации вашего собственного ClassLoader. Поскольку JRE поддерживает только доступ к потоку, как показано выше, вам придется сканировать линейно, чтобы найти запрошенный ресурс/класс или повторить один раз и сохранить записи в Map.

Одной из альтернатив реализации ClassLoader состоит в реализацию пользовательских URL обработчик для использования вместе с URLClassLoader, который уменьшает задачу к поиску, как описано выше:

final Map<String,byte[]> map=new HashMap<>(); 
try(JarInputStream is=new JarInputStream(new ByteArrayInputStream(buffer))) { 
    for(;;) { 
     JarEntry nextEntry = is.getNextJarEntry(); 
     if(nextEntry==null) break; 
     final int est=(int)nextEntry.getSize(); 
     byte[] data=new byte[est>0? est: 1024]; 
     int real=0; 
     for(int r=is.read(data); r>0; r=is.read(data, real, data.length-real)) 
      if(data.length==(real+=r)) data=Arrays.copyOf(data, data.length*2); 
     if(real!=data.length) data=Arrays.copyOf(data, real); 
     map.put("/"+nextEntry.getName(), data); 
    } 
} 
URL u=new URL("x-buffer", null, -1, "/", new URLStreamHandler() { 
    protected URLConnection openConnection(URL u) throws IOException { 
     final byte[] data = map.get(u.getFile()); 
     if(data==null) throw new FileNotFoundException(u.getFile()); 
     return new URLConnection(u) { 
      public void connect() throws IOException {} 
      @Override 
      public InputStream getInputStream() throws IOException { 
       return new ByteArrayInputStream(data); 
      } 
     }; 
    } 
}); 
try(URLClassLoader cl=new URLClassLoader(new URL[]{u})) { 
    cl.loadClass(« a class from your JarFile buffer »); 
} 
Смежные вопросы