Загружать банку динамически

В моем Java-приложении я прочитал файл jar (упакованный с плагином Maven Shade) в поток байтов. В банке есть класс точки входа, определенный в POM.xml

<build>
  ...
  <plugins>
    ...
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>com.mycompany.TheEntryPoint</mainClass>
          </manifest>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>

Как мне динамически загрузить такой класс в мое Java-приложение?

Обновление:

  • JAR загружается как поток байтов и не находится в файловой системе или URL-адресе.

person quarks    schedule 22.11.2012    source источник
comment
Не могли бы вы пояснить вашу последнюю фразу, я случайно вам поверил на слово.   -  person Jesus Ramos    schedule 22.11.2012
comment
@JesusRamos случайно слово? Ироничный.   -  person millimoose    schedule 22.11.2012
comment
@millimoose В этом и был смысл :)   -  person Jesus Ramos    schedule 22.11.2012
comment
@JesusRamos Да, извините, уже исправил грамматику   -  person quarks    schedule 22.11.2012


Ответы (1)


Самый простой способ сделать это — использовать URLClassLoader вместо того, чтобы пытаться сделать это с нуля из потока байтов. Вы всегда можете записать .jar во временный файл и создать для него URL-адрес.

Код будет выглядеть примерно так:

URLClassLoader loader = new URLClassLoader(
    new URL[] {new URL("file://...")},
    Thread.currentThread().getContextClassLoader());

loader.loadClass("com.mycompany.TheEntryPoint");

Вы также можете автоматически определить имя основного класса (или вызвать его) с помощью JarURLConnection. (У Oracle также есть руководство по использованию этого класса.)

person millimoose    schedule 22.11.2012
comment
Ваш JarURLConnection ссылается на java.lang.Thread. Возможно, вы захотите рассмотреть его как ссылку на docs.oracle. com/javase/7/docs/api/java/net/. - person Ryan Amos; 22.11.2012
comment
@RyanAmos К сожалению, там возникла путаница с содержимым буфера обмена. Спасибо, что взялись за это. - person millimoose; 22.11.2012
comment
@millimoose У меня действительно нет особого выбора, кроме как читать из байтового потока, банка не находится в каталоге файлов или URL-адресе - person quarks; 22.11.2012
comment
@xybrek Как я уже сказал, вы можете записать поток байтов во временный файл и использовать для этого URL-адрес. Если по какой-то причине вам не разрешено использовать временные файлы, но это маловероятно. - person millimoose; 22.11.2012
comment
@xybrek Что ж, чтобы обойти это довольно бессмысленное ограничение, вам, вероятно, придется делать что-то с нуля. Подкласс ClassLoader, переопределите findClass() (см. документацию для ClassLoader< /a>) и обратитесь к источник URLClassLoader, чтобы посмотреть, как он читает JAR-файлы. Вы должны иметь возможность повторно использовать или копировать некоторые из них. - person millimoose; 23.11.2012
comment
@xybrek (Из любопытства, по какой причине вы не можете записывать временные файлы? Мне это кажется довольно бессмысленным ограничением.) - person millimoose; 23.11.2012
comment
@millimoose Я использую Google AppEngine (GAE), поэтому я могу записывать файлы из-за его ограничений там (в основном из-за того, что приложения, созданные для него, распространяются по своей природе) - person quarks; 23.11.2012
comment
@millimoose В любом случае, сначала я пробую код в обычной среде JVM, но получаю ClassNotFoundException, хотя я проверил банку и класс там. Есть ли способ перечислить, какие классы из URLClassLoader? - person quarks; 23.11.2012
comment
@xybrek Я так не думаю. Путь к классу ClassLoader должен работать, просматривая записи пути к классам по порядку и пытаясь найти класс в каждом из них, т.е. они не обязательно анализируют свое содержимое заранее. Если URLClassLoader делает это (это была бы правильная оптимизация), определенно не будет никакого API, чтобы посмотреть его индекс известных классов. - person millimoose; 23.11.2012
comment
@xybrek Если вы получаете ClassNotFoundException, проверьте, можете ли вы открыть файл JAR и файл класса вручную, используя / URL-адреса, которые использует URLClassLoader. Вполне возможно, что я сделал ошибку, вы не должны использовать file:// URL-адреса для указания на .jars. Вы можете убедиться в этом, посмотрев на URLClassLoader, который Java использует по умолчанию - если вы запустите отладчик, вы сможете увидеть список используемых им URL-адресов. (URLClassPath ucp поле - person millimoose; 23.11.2012