Исполняемый военный файл, который запускает причал без maven

Я пытаюсь создать «исполняемый» файл войны (java -jar myWarFile.war), который запустит веб-сервер Jetty, на котором размещено веб-приложение, содержащееся в файле WAR, который я выполнил.

Я нашел страницу, на которой описано, как сделать то, что Я ищу:

Однако следование этому совету вместе с тем, как я думаю, что я должен сделать исполняемый файл jar (war), не работает.

У меня есть задача Ant, создающая файл WAR с манифестом, который выглядит так:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 1.5.0_18-b02 (Sun Microsystems Inc.)
Main-Class: Start

Содержимое файла WAR выглядит так:

> Start.class
> jsp
>   build.jsp 
> META-INF  
>   MANIFEST.MF
> WEB-INF
>   lib
>     jetty-6.1.22.jar
>     jetty-util.6.1.22.jar

Когда я пытаюсь выполнить файл WAR, возникает ошибка:

Exception in thread "main" java.lang.NoClassDefFoundError: org/mortbay/jetty/Handler
Caused by: java.lang.ClassNotFoundException: org.mortbay.jetty.Handler
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Could not find the main class: Start. Program will exit.

Кажется, здесь две ошибки: одна, когда кажется, что файлы JAR не могут быть найдены, и одна, когда не может быть найден класс Start.

Чтобы исправить первую ошибку, я поместил JAR-файлы Jetty в базу WAR-файла и попытался снова — та же ошибка. Я также попытался добавить WEB-INF/lib/<specific-JAR-files> к атрибуту Class-Path манифеста. Это тоже не сработало.

Кто-нибудь знает, что я делаю правильно/неправильно и как я могу запустить этот исполняемый файл WAR?


person twilbrand    schedule 16.03.2010    source источник
comment
У вас должен быть файл .war? Почему бы не иметь файл .jar, содержащий файл .war, дистрибутив причала и основной класс, который программно запускает причал и загружает ваше веб-приложение в контекст.   -  person whaley    schedule 24.04.2010


Ответы (9)


ссылка в вашем вопросе содержит большую часть что вам нужно. Тем не менее, есть несколько вещей, которые необходимо сделать в дополнение к этому.

Любые файлы классов, которые нужны Jetty для запуска, должны быть расположены в корне файла войны, когда он упакован. Мы можем использовать Ant, чтобы сделать это за нас, прежде чем мы <war> файл. Файлу манифеста войны также потребуется атрибут Main-Class для запуска сервера.

Вот шаг за шагом:

Создайте свой класс сервера Jetty:

Это адаптировано из предоставленной вами ссылки.

package com.mycompany.myapp;

import java.io.File;
import java.net.URL;
import java.security.ProtectionDomain;

import org.mortbay.jetty.Server;
import org.mortbay.jetty.webapp.WebAppContext;

public final class EmbeddedJettyServer
{
    public static void main(String[] args) throws Exception
    {
        int port = Integer.parseInt(System.getProperty("port", "8080"));
        Server server = new Server(port);

        ProtectionDomain domain = EmbeddedJettyServer.class.getProtectionDomain();
        URL location = domain.getCodeSource().getLocation();

        WebAppContext webapp = new WebAppContext();
        webapp.setContextPath("/");
        webapp.setDescriptor(location.toExternalForm() + "/WEB-INF/web.xml");
        webapp.setServer(server);
        webapp.setWar(location.toExternalForm());

        // (Optional) Set the directory the war will extract to.
        // If not set, java.io.tmpdir will be used, which can cause problems
        // if the temp directory gets cleaned periodically.
        // Your build scripts should remove this directory between deployments
        webapp.setTempDirectory(new File("/path/to/webapp-directory"));

        server.setHandler(webapp);
        server.start();
        server.join();
    }
}

Чтобы узнать, что здесь можно настроить, посмотрите ссылку Документация по Jetty API.

Постройте войну с Ant:

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

<target name="war" description="--> Creates self-executing war">
  <property name="staging.dir" location="${basedir}/staging"/>
  <property name="webapp.dir" location="${basedir}/src/webapp"/>

  <mkdir dir="${staging.dir}"/>

  <!-- assumes you have all of your war content (excluding classes and libraries) already structured in a directory called src/webapp -->
  <!-- e.g. -->
  <!-- src/webapp/index.html -->
  <!-- src/webapp/WEB-INF/web.xml -->
  <!-- src/webapp/WEB-INF/classes/my.properties -->
  <!-- etc ... -->
  <copy todir="${staging.dir}">
    <fileset dir="${webapp.dir}" includes="**/*"/>
  </copy>

  <unjar dest="${staging.dir}">
    <!-- you'll have to locate these jars or appropriate versions; note that these include JSP support -->
    <!-- you might find some of them in the downloaded Jetty .tgz -->
    <fileset dir="path/to/jetty/jars">
      <include name="ant-1.6.5.jar"/>
      <include name="core-3.1.1.jar"/>
      <include name="jetty-6.1.24.jar"/>
      <include name="jsp-2.1-glassfish-2.1.v20091210.jar"/><!-- your JSP implementation may vary -->
      <include name="jsp-api-2.1-glassfish-2.1.v20091210.jar"/><!-- your JSP implementation may vary -->
      <include name="servlet-api-2.5-20081211.jar"/><!-- your Servlet API implementation may vary -->
    </fileset>
    <patternset><!-- to exclude some of the stuff we don't really need -->
      <exclude name="META-INF/**/*"/>
      <exclude name="images/**/*"/>
      <exclude name=".options"/>
      <exclude name="about.html"/>
      <exclude name="jdtCompilerAdapter.jar"/>
      <exclude name="plugin*"/>
    </patternset>
  </unjar>

  <!-- copy in the class file built from the above EmbeddedJettyServer.java -->
  <copy todir="${staging.dir}">
    <fileset dir="path/to/classes/dir" includes="com/mycompany/myapp/EmbeddedJettyServer.class"/>
  </copy>

  <war destfile="myapp.war" webxml="${webapp.dir}/WEB-INF/web.xml">
    <fileset dir="${staging.dir}" includes="**/*"/>
    <classes dir="path/to/classes/dir"/><!-- your application classes -->
    <lib dir="path/to/lib/dir"/><!-- application dependency jars -->
    <manifest>
      <!-- add the Main-Class attribute that will execute our server class -->
      <attribute name="Main-Class" value="com.mycompany.myapp.EmbeddedJettyServer"/>
    </manifest>
  </war>

  <delete dir="${staging.dir}"/>
</target>

Выполнить войну:

Если выше все настроено правильно, вы сможете:

java -jar myapp.war

// or if you want to configure the port (since we are using the System property in the code)

java -Dport=8443 -jar myapp.war
person Rob Hruska    schedule 09.07.2010
comment
Очень-очень незначительный комментарий: при исключении папок из банок (в ‹unjar›) мы можем использовать **/META-INF/** вместо META-INF/**/*, чтобы исключить фактическую папку, а также содержимое папки. В противном случае корневая папка все еще включена. - person joscarsson; 26.10.2012
comment
Почему вы unjar используете все jar-файлы с зависимостями? Они включаются в каталог WEB-INF/lib. - person RTF; 02.05.2014
comment
@RTF - это было давно, но я считаю, что это было потому, что эти классы являются зависимостями от самой исполняемой войны (например, причала, EmbeddableJettyServer и т. д.), и когда вы выполняете войну, она не может загрузить их из встроенного jar ( внутри себя) - они должны быть классами, связанными с войной. - person Rob Hruska; 02.05.2014

Это адаптация для Maven ответа @RobHruska. Он просто копирует файлы основного класса и объединяет JAR-файлы Jetty в WAR-файл, ничего нового, просто чтобы упростить вашу жизнь, если вы, как и я, новичок в Maven:

<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
        <execution>
            <id>move-main-class</id>
            <phase>compile</phase>
            <configuration>
                <tasks>
                    <copy todir="${project.build.directory}/${project.build.finalName}">
                        <fileset dir="${project.build.directory}/${project.build.finalName}/WEB-INF/classes/">
                            <include name="main/*.class" />
                        </fileset>
                    </copy>

                    <unjar dest="${project.build.directory}/${project.build.finalName}">
                        <!-- you'll have to locate these jars or appropriate versions; note that these include JSP support -->
                        <!-- you might find some of them in the downloaded Jetty .tgz -->
                        <fileset dir="${project.build.directory}/${project.build.finalName}/WEB-INF/lib/">
                            <include name="ant-1.6.5.jar"/>
                            <!--<include name="core-3.1.1.jar"/>-->
                            <include name="jetty*"/>
                            <include name="servlet-api*"/>
                        </fileset>

                        <patternset><!-- to exclude some of the stuff we don't really need -->
                            <exclude name="META-INF/**/*"/>
                            <exclude name="images/**/*"/>
                            <exclude name=".options"/>
                            <exclude name="about.html"/>
                            <exclude name="jdtCompilerAdapter.jar"/>
                            <exclude name="plugin*"/>
                        </patternset>
                    </unjar>
                </tasks>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
</plugin> 
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <archiveClasses>true</archiveClasses>
        <archive>
            <manifest>
                <mainClass>main.Main</mainClass> 
            </manifest>
        </archive>
    </configuration>
</plugin>
person AhHatem    schedule 01.05.2012
comment
Как заставить его выполняться? Я обычно строю с mvn clean compile war:war, но maven-antrun-plugin никогда не выполняется. - person Ragnar; 15.01.2015

Мы выяснили это, используя плагин jetty-console-maven.

Всякий раз, когда вы запускаете пакет mvn, он создает еще одну войну, которую можно использовать с java -jar whatpackage-runnable.war

        <plugin>
            <groupId>org.simplericity.jettyconsole</groupId>
            <artifactId>jetty-console-maven-plugin</artifactId>
            <version>1.45</version>
            <executions>
                <execution>
                    <goals>
                        <goal>createconsole</goal>
                    </goals>
                </execution>
            </executions>

            <configuration>
                <additionalDependencies>
                    <additionalDependency>
                        <artifactId>jetty-console-requestlog-plugin</artifactId>
                    </additionalDependency>
                    <additionalDependency>
                        <artifactId>jetty-console-gzip-plugin</artifactId>
                    </additionalDependency>
                    <additionalDependency>
                        <artifactId>jetty-console-ajp-plugin</artifactId>
                    </additionalDependency>
                    <additionalDependency>
                        <artifactId>jetty-console-startstop-plugin</artifactId>
                    </additionalDependency>
                </additionalDependencies>
            </configuration>
        </plugin>

Он также генерирует сценарии init.d и все остальное для вас!

person Rafael Sanches    schedule 21.03.2012
comment
Есть ли документация о том, как это работает? Как объявить класс, запускающий Jetty? И, наконец, требует ли это, чтобы причальные банки были причиной войны? - person Jose Martinez; 08.08.2014
comment
он делает все за вас .. вы просто запускаете пакет mvn, и он генерирует для вас войну. - person Rafael Sanches; 01.04.2016

Hudson решает именно эту проблему, используя контейнер сервлетов Winstone, который напрямую поддерживает этот вариант использования. http://winstone.sourceforge.net/#embedding

Возможно, это сработает для вас?

person Thorbjørn Ravn Andersen    schedule 17.03.2010
comment
Jetty в конечном счете был слишком запутанным с нулевой помощью в Интернете, которую я мог найти. Попытка сделать так, чтобы моя война содержала винстон, также оказалась проблематичной, но как только я поместил свое приложение в исходный код винстоуна, не распакованный в банку, а затем повторно заархивировал его, все идет нормально. - person twilbrand; 18.03.2010
comment
Kohsuke с тех пор устал поддерживать Winstone, поэтому он заменил его Winstone-совместимой оболочкой вокруг Jetty. jenkins-ci.361315. n4.nabble.com/ - person Thorbjørn Ravn Andersen; 11.12.2013

Несмотря на то, что это довольно старый вариант, другая альтернатива Jetty 8 — просто включить банки Jetty в качестве зависимостей в ваш pom и добавить в свой pom следующее (в отличие от сценария ant, который распаковывает войну и переупаковывает ее):

            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <createDependencyReducedPom>true</createDependencyReducedPom>
                        <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>JettyStandaloneMain</mainClass>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <!-- The main class needs to be in the root of the war in order to be 
            runnable -->
        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <executions>
                <execution>
                    <id>move-main-class</id>
                    <phase>compile</phase>
                    <configuration>
                        <tasks>
                            <move todir="${project.build.directory}/${project.build.finalName}">
                                <fileset dir="${project.build.directory}/classes/">
                                    <include name="JettyStandaloneMain.class" />
                                </fileset>
                            </move>
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
person Rodney Beede    schedule 01.07.2011

Я так понимаю, что «без maven» вам нужен jar, который вы можете запускать сам по себе, а не с «mvn jetty: run» - не то чтобы вы вообще не хотите использовать maven.

Мне потребовалось много времени, чтобы понять это, потому что я нашел много вариантов, и ни один из них не был настолько простым. В конце концов я нашел этот плагин maven от simplericity. Это прекрасно работает.

person schmmd    schedule 02.11.2011
comment
Спасибо, но знаете ли вы, как настроить его, например, для добавления контекстного пути? - person Hunsu; 06.04.2015

Это мой пример экстракта ANT. Идея состоит в том, чтобы распаковать зависимости Jetty, а затем включить их локально, как обычный файл JAR:

<!-- Hack: Java doesn't support jars within jars/wars -->
<unjar src="${lib.dir}/container/jetty.jar" dest="${build.dir}/unjar"/>
<unjar src="${lib.dir}/container/jetty-util.jar" dest="${build.dir}/unjar"/>
<unjar src="${lib.dir}/container/servlet-api.jar" dest="${build.dir}/unjar"/>
<unjar src="${lib.dir}/container/jsp-api.jar" dest="${build.dir}/unjar"/>

<!-- Build war file as normal, just including the compiled and unjar'ed files -->
<war destfile="${war.file}" webxml="${config.dir}/web.xml">
    <fileset dir="${build.dir}/classes"/>
    <fileset dir="${build.dir}/unjar"/>
    <fileset dir="${resources.dir}" excludes="*.swp"/>
    <lib dir="${lib.dir}/runtime"/>
    <manifest>
        <attribute name="Main-Class" value="Start"/>
    </manifest>
</war>

Note:

Каталог WEB-INF/lib предназначен для зависимостей веб-приложений. В данном случае мы упаковываем WAR-файл, чтобы при запуске он работал как обычный JAR-файл Jetty.

person Mark O'Connor    schedule 22.03.2010

  • Помещение .jars в корень файла .war ничего не делает
  • Помещение .jars внутрь WEB-INF/lib не помогает JVM найти файлы Jetty даже для запуска вашего .war. Ставить их "поздно".
  • Помещение .jars в манифест Class-Path работает только для внешних файлов .jar, а не для тех, которые содержатся в .jar

Так что делать?

  • Используйте сценарий сборки, чтобы просто объединить все нужные файлы .jar в файл .war. Это требует немного дополнительной работы. Это также немного уродливо в том смысле, что скомпилированный код является частью обслуживаемых файлов в .war
  • Добавьте зависимые .jars в путь к классам JVM с помощью «java -cp jetty.jar:... ..." Работает, хотя этот вид побеждает цель одного автономного .war
person Sean Owen    schedule 17.03.2010
comment
@ Шон, он не помещает банки в корень файла .war, он помещает файл класса, и это совершенно правильно (как указывает его ссылка) - person Kannan Ekanath; 17.03.2010
comment
Его оригинальный пост показывает файлы .jar в .war, в WEB-INF/lib. Затем он упоминает, что положил .jars в основу .war. Ваш последующий пост показывает .jars в каталоге lib/, так что вы имеете в виду? Я могу ошибаться, так как сам не пробовал, но как в этом случае JVM находит классы Jetty? Сообщение, которое вы упомянули, показывает, что Maven создает зависимости вместе, а вывод Maven, который я когда-либо видел, просто объединяет файлы .class в один .jar/.war, что было моим первым ответом. - person Sean Owen; 17.03.2010

Я делал нечто подобное раньше, но вы запускаете приложение как «java -jar xxx.war»? У вас есть только 2 баночки, и этого, я думаю, будет недостаточно. Также попробуйте использовать Jetty 7.0.0M1 (последняя версия). Когда я добавил jetty-server и jetty-webapp в качестве двух зависимостей (они из org.eclipse.jetty), я получаю следующие файлы jar в каталоге lib. К вашему сведению, org.mortbay.jetty.Handler находился в файле jetty-server*.jar.

  • причал-продолжение-7.0.0.M1.jar
  • причал-http-7.0.0.M1.jar
  • причал-io-7.0.0.M1.jar
  • причал-безопасность-7.0.0.M1.jar
  • причал-сервер-7.0.0.M1.jar
  • причал-сервлет-7.0.0.M1.jar
  • причал-util-7.0.0.M1.jar
  • причал-webapp-7.0.0.M1.jar
  • причал-xml-7.0.0.M1.jar
person Kannan Ekanath    schedule 17.03.2010