В памяти jar / файл класса выполнения - PullRequest
4 голосов
/ 17 июля 2010

У меня есть файл jar (скажем, app.jar) в определенном месте, доступный как файл / поток с http-сервера.Проблема в том, что app.jar сам по себе является часто обновляемым файлом jar, который регулярно обновляется на сервере.У меня есть другой файл jar (скажем, load.jar), который просто загружается любым пользователем.Во время выполнения пользователь запускает load.jar, который требуется для загрузки app.jar в отдельном процессе, сохраняя app.jar в памяти (без кеширования на диск), затем выполняет app.jar и завершает себя (load).банка).Возможно ли это сделать?Любая помощь высоко ценится.Заранее спасибо.С уважением, KT

--------------------------- Обновление.

Привет,

Спасибо всем за ответ.Однако, я думаю, я не дал полную картину.Прилагается изображение текст ссылки , изображающее сценарий.4 баночки (фактические общие исполнители) размещены на центральном сервере.Они часто обновляются (возможно, 3-4 раза в день, первоначально до одного раза в день, в конце концов).Локальный сервер в одном из участников размещен, который инициализирован.Модуль запуска на локальном сервере загружает все 4 двоичных файла и сохраняет их в памяти - без кэширования на диск.Эти файлы JAR являются самодостаточными и не зависят от какой-либо библиотеки на «Локальном сервере» - они фактически вызывают файлы JAR с «Локального сервера».JAR-файл клиента в конечном итоге размещается на «Локальном сервере» и пересылается его клиентам по требованию через веб-приложение на «Локальном сервере».Кроме того, Launcher должен выйти, вызвав загруженный Main JAR с сервера в отдельной JVM.

С уважением, KT

Ответы [ 4 ]

3 голосов
/ 21 июля 2010

OK.Прежде чем я поместил ссылку на статью szegedi в свой предыдущий ответ (честно), я создал прототип jar-лаунчера, который мог бы обрабатывать URL-адреса.Как сказал автор, это было не сложно, вероятно, не завершено.Прилагается ниже.Я думаю, что это 1/3 того, что вам нужно.Ваш пользователь говорит (что-то вроде):

java -jar load.jar http://localhost:8080/app.jar

load.jar выполняет две роли: (1) вызывает JarLauncher (ниже) в качестве основного класса (2) подать app.jar на локальный порт (перед вызовом JarLauncher).Поэтому load.jar считывает свои аргументы, чтобы выяснить, какое приложение нужно запустить.

Наконец (жесткий бит): вы должны сделать так, чтобы URLClassLoader не попадал на временный диск.Как говорится в статье szegedi, это не легко.В качестве альтернативы вы можете написать свой собственный загрузчик классов с поддержкой сети, который не кэширует диск, как мое первое предложение - загружать URL-адрес в память в виде байтового потока из URL-соединения, декодировать его как JarInputStream и удовлетворять вызовы loadClass /.findResource из этого потока в памяти.

У вас впереди много работы.Удачи.

Извиняюсь за размер текста лицензии, но он позволяет вам делать то, что вам нравится с кодом, если вы не обвиняете меня (BSD).

-Симон.



/*
 * One-JAR(TM) (http://www.simontuffs.com/one-jar).  Copyright (c) 2004-2010, 
 * P. Simon Tuffs (simon@simontuffs.com).   All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.  
 *
 * Neither the name of P. Simon Tuffs, nor the names of any contributors, 
 * nor the name One-JAR may be used to endorse or promote products derived 
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Including this file inside the built One-JAR file conforms with these terms.
 */

import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.jar.JarInputStream;

/**
 * Programmatic equivalent of what happens when you say "java -jar <jar-file.jar>".
 * A better solution to debugging/running Jar files inside an IDE.
 * @author simon
 *
 */
public class JarLauncher {

    public static URL getURL(String string) throws MalformedURLException {
        try {
            return new URL(string);
        } catch (MalformedURLException x) {
            return new URL("file:" + string);
        }
    }

    public static void main(String args[]) throws Exception {
        if (args.length < 1) {
            System.out.println("Usage: java [-Dkey=value...] JarLauncher <jar-file.jar>");
            System.exit(1);
        }
        String jar = args[0];
        args = Arrays.copyOfRange(args, 1, args.length);
        List<URL> urls = new ArrayList<URL>();
        // Main jar on the URL path.
        // Dig out the main class.
        urls.add(getURL(jar));
        URL jarurl = urls.get(0);
        JarInputStream jis = new JarInputStream(jarurl.openStream());
        String main = jis.getManifest().getMainAttributes().getValue("Main-Class");
        // OK to split on space, because embedded space is %20
        String classpaths[] = jis.getManifest().getMainAttributes().getValue("Class-Path").split(" ");
        for (String classpath: classpaths) {
            urls.add(getURL(classpath));
        }
        URLClassLoader loader = new URLClassLoader(urls.toArray(new URL[0]));
        Class<?> cls = loader.loadClass(main);
        Thread.currentThread().setContextClassLoader(loader);
        Method m = cls.getMethod("main", new Class[]{new String[0].getClass()});
        m.invoke(null, new Object[]{args});

    }

}

2 голосов
/ 19 июля 2010

Я предложу взглянуть на http://jcloader.sourceforge.net/

Это имеет большую гибкость и довольно богатый набор функций.

  JarClassLoader jcl = new JarClassLoader();

  //Loading classes from different sources
  jcl.add("myjar.jar");
  jcl.add(new URL("http://myserver.com/myjar.jar"));
  jcl.add(new FileInputStream("myotherjar.jar"));
  jcl.add("myclassfolder/");

  //Recursively load all jar files in the folder/sub-folder(s)
  jcl.add("myjarlib/");

  JclObjectFactory factory = JclObjectFactory.getInstance();

  //Create object of loaded class
  Object obj = factory.create(jcl, "mypack.MyClass");
2 голосов
/ 20 июля 2010

Дальнейшее редактирование:

Я просканировал сеть и наткнулся на эту прекрасную статью, которая также может иметь отношение к вашему вопросу: http://www.szegedi.org/articles/remotejars.html

В этом случае большая часть того, что я написал нижене имеет значения, но я все равно оставлю это на всякий случай.

Редактировать:

Хорошо, я думаю, что я получаю лучшее представление о ваших требованиях.Требования, однако, хитры, поэтому позвольте мне рассказать вам, что я думаю, что вы пытаетесь сделать, и затем я посмотрю, какие решения предлагает.Я, вероятно, пойму это неправильно, тогда мы сделаем это снова.

Требования:

Механизм распределенного кэширования для обслуживания приложений WebStart.Приложения (.jars) меняются регулярно.Они автономны.Вы хотите иметь локальный кэш, способный обслуживать файлы JAR Webstart, полученные с центрального сервера, сохраняя их в памяти.Я не понимаю ваших требований к выходу.

Решения?

Вам может потребоваться веб-сервер, на котором можно разместить веб-приложение, которое будет считывать обновленные банки приложений в память, а затем обслуживать их.их на веб-запуск.Вам нужно будет использовать веб-сервер, такой как Jetty / Tomcat, и написать простое веб-приложение для запуска под ним.Веб-приложение будет опрашивать центральный сервер на предмет обновлений приложения и сделает файлы приложения доступными для веб-запуска через URL-адреса, которые он обслуживает.Опрос центрального сервера, вероятно, имеет больше смысла, чем когда центральный сервер отправляет новые приложения на локальные серверы из-за брандмауэра и масштабируемости.

Я не знаю ни одного готового веб-приложения, которое бы делало это, может быть одно.

Но, как я уже сказал, я, вероятно, все еще не понимаю этого.Требования: надо любить их.


Я собираюсь сделать некоторые предположения в этом ответе, основываясь на вашем вопросе.Звучит так, как будто вы хотите кэшировать «app.jar» с удаленной машины на время существования «load.jar» на локальной машине, чтобы позволить изолировать «load.jar» от изменений в «app.jar»."в течение своей жизни.Это кажется хорошей идеей: я ожидаю, что если вы используете URLClassLoader для переноса «app.jar» в пространство «load.jar», то обновление в середине выполнения может привести к хаосу.

Также звучит так, как будто вы не хотите, чтобы «load.jar» делал копию «app.jar» на диске - я думаю, что это разумная цель: кто хочет, чтобы старые файлы jar были разбросаны помашина?кто хочет проблемы с разрешением, связанные с попыткой записи временных файлов?

Учитывая эти цели, вам нужно найти или реализовать загрузчик классов, который делает снимок «app.jar», когда «load.jar» впервые попадает в класс внутри него.Это не сложно: мне пришлось сделать нечто подобное в моем One-JAR JarClassLoader, который загружает файлы Jar изнутри файлов Jar.Во время запуска он загружает все найденные байты в память, а затем разрешает классы по требованию, используя это хранилище памяти.Хотя это, возможно, менее эффективно, чем отложенная загрузка, оно быстрое и стабильное и может решить вашу проблему.

К сожалению, One-JAR не позволяет сетевым (или файловым) ресурсам кэшироваться таким образом.Он использует делегирование через обычный загрузчик классов URL-адресов, что делает его не кэширующим ваши удаленные ресурсы.

Я предлагаю вам взглянуть на хранилище CVS: http://one -jar.cvs.sourceforge.net/viewvc/one-jar/one-jar/src/com/simontuffs/onejar/JarClassLoader.java?revision=1.58&view=markup

около строки 678. Не пугайтесь размераэтого класса, это куча особых случаев для обработки, ну, в частности, особых случаев.

Если бы мне пришлось создавать что-то с нуля, я бы создал подкласс URLClassLoader, переопределил методы loadClass, getResource и findResource (см., Например, строку 281, где One-JAR делает это для своих собственных нужд инверсии загрузчика классов)вставьте кэширование байт-кода, загрузив весь «app.jar» в память в виде хэш-таблицы байтового массива, индексируемой ключами имен классов / ресурсов (снова это One-JAR), и затем вы будете кэшированы в памяти.

Надеюсь, это поможет.

-. Симон

0 голосов
/ 17 июля 2010

Вы уже посмотрели класс URLClassloader?

Здесь может быть полезен JarClassloader: http://www.java.happycodings.com/Other/code27.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...