Выполнение файла JAR в другом приложении Java

Я пытаюсь запустить файл External Jar, фактически не вставляя его в саму банку. Потому что файл jar должен находиться в той же папке, что и основной файл jar.

Итак, в основном файле jar я хочу выполнить другой исполняемый файл jar, и мне нужно знать, когда заканчивается файл jar, И когда вы закрываете основной файл jar, файл jar, который запускается в файле jar нужно закрыть,

В настоящее время я делаю это, используя этот код:

public void LaunchLatestBuild()
  {
    try {
      String path = new File(".").getCanonicalPath() + 
        "\\externaljar.jar";
      List commands = new ArrayList();
      commands.add(getJreExecutable().toString());
      commands.add("-Xmx" + this.btd_serverram + "M");
      commands.add("-Xms" + this.btd_serverram + "M");
      commands.add("-jar");
      commands.add(path);

      int returnint = launch(commands); //It just waits and stops the tread here. And my Runtime.getRuntime().addShutdownHook doesn't get triggerd.

      if (returnint != 201) //201 is a custom exit code I 'use' to know when the app needs a restart or not.
      {
        System.out.println("No restart needed! Closing...");
        System.exit(1);
      }
      else
      {
        CloseCraftBukkit();

        Launcher.main(new String[] { "" });
      }
    }
    catch (Exception e)
    {
      System.out.println(e.toString());
      e.printStackTrace();
    }
  }
  public int launch(List<String> cmdarray) throws IOException, InterruptedException
  {
    byte[] buffer = new byte[1024];

    ProcessBuilder processBuilder = new ProcessBuilder(cmdarray);
    processBuilder.redirectErrorStream(true);
    this.CBProcess = processBuilder.start();
    InputStream in = this.CBProcess.getInputStream();
    while (true) {
      int r = in.read(buffer);
      if (r <= 0) {
        break;
      }
      System.out.write(buffer, 0, r);
    }

    return this.CBProcess.exitValue();
  }

Ограничения этого кода:

  • Не закрывает мой java-процесс externaljar.jar при выходе из основного приложения.
  • Невозможно перенаправить ввод с основной консоли на внешний jar.

Это самые важные вещи, которые мне нужны.

Я надеюсь, что кто-то может сказать мне, как я должен это сделать.

Текущий исходный код доступен по адресу: http://code.google.com/p/bukkit-to-date/


person WMisiedjan    schedule 11.02.2011    source источник
comment
Можете ли вы опубликовать код для launch   -  person dfb    schedule 11.02.2011
comment
@spintheblack: добавлено в основной пост   -  person WMisiedjan    schedule 11.02.2011


Ответы (1)


Почему вы не можете просто установить свой путь к классам так, чтобы он включал вторую банку, а затем вы могли бы просто использовать ее как библиотеку? Вы даже можете вызвать метод MainClass.main() вручную, если вы действительно хотите, чтобы он выполнялся, но из той же виртуальной машины и без порождения отдельного процесса.

РЕДАКТИРОВАТЬ: Если вы не знаете имя файла jar при запуске вашего приложения, но вы узнаете это только во время выполнения, чтобы вызвать его, создайте файл URLClassLoader с указанием пути к файлу jar, а затем:

URLClassLoader urlClassLoader = new URLClassLoader(
        new File("/path/to/your/jar/file.jar").toURI().toURL() );

ClassLoader cl = Thread.currentThread().getContextClassLoader();
// switch to your custom CL
Thread.currentThread().setContextClassLoader(urlClassLoader);
// do your stuff with the other jar
// ....................
// now switch back to the original CL
Thread.currentThread().setContextClassLoader(cl);

Или просто возьмите ссылку на класс в другой банке и используйте отражение:

Class<?> c = urlClassLoader.loadClass("org.ogher.packag.ClassFromExternalJar");
person Costi Ciudatu    schedule 11.02.2011
comment
Я так хочу, Но дело в том, что файл постоянно меняется. Это проблема при использовании пути к классам? Потому что я думал, что он импортирует весь файл jar, верно? И этого файла тоже может не быть. - person WMisiedjan; 11.02.2011
comment
В этом случае одним из решений было бы иметь собственный загрузчик классов в качестве дочернего элемента системного, а затем вы можете загружать все, что хотите, когда вам это нужно. - person Costi Ciudatu; 11.02.2011
comment
Кто-нибудь может объяснить, как это сделать? Мне также нужно иметь возможность обнаружить, что внешний jar остановился. - person WMisiedjan; 11.02.2011
comment
Что именно вы подразумеваете под остановкой внешней банки? (Кстати, я попытался объяснить с правкой). - person Costi Ciudatu; 11.02.2011
comment
Когда внешний jar пытается завершить процесс. Мне нужно это знать. - person WMisiedjan; 11.02.2011
comment
Но поскольку вы вызываете методы для объектов, вы либо вызываете их синхронно, либо можете присоединиться к другому потоку, чтобы дождаться его, так что это вообще не проблема. - person Costi Ciudatu; 11.02.2011
comment
Я снова отредактировал ответ, чтобы сделать его немного более явным... Чтобы перефразировать вышеизложенное, теперь нет jar-файла, который нужно завершать, только вызовы методов Java, которые вы можете выполнять синхронно или join(). - person Costi Ciudatu; 11.02.2011
comment
@WMisiedjan вам нужно будет установить собственный SecurityManager с помощью System.setSecurityManager(), чтобы перехватывать эти запросы и превращать их в исключения. download.oracle.com/javase/ 1.4.2/docs/api/java/lang/ _______________ Для загрузчика классов вы можете использовать java.net.URLClassloader для загрузки его основного класса (findClass()) и выполнения его основного метода с отражением.download.oracle .com/javase/1.4.2/docs/api/java/net/ - person josefx; 11.02.2011
comment
ОТЛИЧНЫЙ! Как мне теперь выполнить, например: 'код' c.getMethod(main, c) - person WMisiedjan; 11.02.2011
comment
Я уже загрузил класс: org.bukkit.craftbukkit.Main Теперь мне нужно только выполнить метод main. - person WMisiedjan; 11.02.2011
comment
попробуйте Method mainMethod = yourClass.getMethod("main", String[].class);, а затем mainMethod.invoke(new String[0]). - person Costi Ciudatu; 11.02.2011
comment
Ага, всем спасибо! Как мне теперь получить код выхода этого метода? - person WMisiedjan; 11.02.2011
comment
@Costi Ciudatu: Вы имеете в виду коды выхода? Потому что мне нужен способ сообщить внешней банке, что основная банка нуждается в перезагрузке. Таким образом, основная банка снова загружает внешнюю банку. - person WMisiedjan; 11.02.2011
comment
Метод main возвращает значение void, поэтому код выхода не используется, поскольку exit отсутствует. - person Costi Ciudatu; 11.02.2011
comment
@Costi Ciudatu: мне нужен способ сообщить основному банку, что внешний банку нужно перезапустить, поэтому основной банку снова загружает внешний банку. - person WMisiedjan; 11.02.2011
comment
@WMisiedjan SecurityManager, о котором я упоминал ранее, должен генерировать исключение при вызове System.exit(), создать подкласс исключения, чтобы добавить код выхода, вы можете прочитать код, когда поймаете его. - person josefx; 11.02.2011
comment
Теперь у меня есть все, что мне нужно, я могу получить код выхода и т. д. Но как мне ВЫГРУЗИТЬ файл jar из виртуальной машины? Так что больше не используется. Потому что тому же приложению необходимо заменить внешний файл jar обновлением для определенного кода выхода. Я уже пробовал некоторые вещи, но без успеха. - person WMisiedjan; 12.02.2011
comment
Просто создайте экземпляр нового URLClassLoader с новым jar-файлом и позвольте сборщику мусора собрать старый CL (не сохраняйте ссылки на этот загрузчик классов или класс, который вы загрузили вместе с ним). - person Costi Ciudatu; 12.02.2011
comment
Что такое ГК? И если вы хотите, вы можете проверить, что у меня сейчас есть: code.google.com/p/bukkit-to-date/source/browse/ - person WMisiedjan; 12.02.2011
comment
GC = Garbage Collector, я постараюсь проверить ваш код и вернуться к вам. - person Costi Ciudatu; 12.02.2011
comment
Хм... первое, что я заметил, вы используете setContextClassLoader(), хотя вы вызываете основной метод через отражение. При использовании отражения нет необходимости изменять загрузчик класса потока. Теперь я все еще не понимаю, в чем твоя проблема. Что значит выгрузить из ВМ? Если вы хотите загрузить другую банку, просто создайте экземпляр еще одного URLClassLoader с новым URL-адресом, и вы получите новую версию. Старая ссылка теряется сама по себе через сборку мусора. Просто убедитесь, что вы не сохраняете загрузчик классов или класс, который вы загружаете, как переменную класса/экземпляра. - person Costi Ciudatu; 13.02.2011
comment
Проблема в том, что мне не нужен другой. Мне нужно, чтобы ТАКОЙ ЖЕ был удален/заменен впоследствии. Я обновил свой код до того, что вы сказали. Я очистил все вары, а затем запустил GC. - person WMisiedjan; 13.02.2011
comment
Неважно, тот же это путь или другой. Просто создайте новый экземпляр URLClassLoader с тем же URL-адресом файла, и это должно быть так. - person Costi Ciudatu; 13.02.2011
comment
Да, но мне нужно заменить его, прежде чем я перезагрузил его. В исходном коде: code.google.com/p/bukkit-to-date. Я пытаюсь удалить файл craftbukkit.jar. Таким образом, я могу потом скопировать туда новую версию, а ЗАТЕМ загрузить ее снова. - person WMisiedjan; 13.02.2011
comment
Теперь я понимаю: вы хотите удалить файл, загруженный в данный момент с помощью URLClassLoader, и Windows не позволит вам это сделать. Это правильно ? - person Costi Ciudatu; 13.02.2011
comment
Метод .close() (который делает именно это: освобождает ресурсы, используемые CL) доступен только для URLClassLoader в Java 7, если честно. В качестве обходного пути я только что нашел альтернативу: org.apache.xbean.classloader.JarFileClassLoader, которая может закрывать соединения с файлами jar. Может быть, это могло бы помочь вам. - person Costi Ciudatu; 13.02.2011
comment
Почему-то Eclipse не знает об org.apache.xbean.classloader.JarFileClassLoader. Возможно, мне нужно загрузить какие-то файлы? Ничего, уже нашел. Спасибо! - person WMisiedjan; 13.02.2011
comment
ДА СПАСИБО! ЭТО ПОЛНОСТЬЮ РАБОТАЕТ СЕЙЧАС! ДЕЙСТВИТЕЛЬНО ЦЕНЮ ЭТО! - person WMisiedjan; 13.02.2011
comment
Теперь у меня возникла проблема: при попытке обнаружить перезапуск он обнаруживает его, но как только я снова выполняю функцию Main() из класса Main, он отключается. Кто-нибудь знает, что вызывает это? И как я могу это предотвратить? - person WMisiedjan; 19.02.2011