web-dev-qa-db-fra.com

Fichier de guerre exécutable qui démarre la jetée sans maven

J'essaie de créer un fichier war "exécutable" (Java -jar myWarFile.war) qui démarrera un serveur Web Jetty qui héberge l'application Web contenue dans le fichier WAR que j'ai exécuté.

J'ai trouvé ne page qui décrivait comment faire ce que je cherchais:

Cependant, suivre ces conseils ainsi que la façon dont je pense que je suis censé faire un pot exécutable (guerre) ne fonctionne pas.

J'ai une tâche Ant créant un fichier WAR avec un manifeste qui ressemble à:

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

Le contenu du fichier WAR ressemble à:

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

Lorsque j'essaie d'exécuter le fichier WAR, l'erreur est:

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.

Il semble y avoir deux erreurs ici: une où il semble que les fichiers JAR sont introuvables, et une où la classe Start est introuvable.

Pour corriger le premier, j'ai mis les fichiers Jetty JAR à la base du fichier WAR et j'ai réessayé - même erreur. J'ai également essayé d'ajouter le WEB-INF/lib/<specific-JAR-files> à la Class-Path attribut du manifeste. Cela n'a pas fonctionné non plus.

Quelqu'un a-t-il une idée de ce que je fais bien/mal et comment obtenir ce fichier WAR exécutable et le faire fonctionner?

52
twilbrand

Le lien que vous avez dans votre question fournit la plupart de ce dont vous avez besoin. Cependant, il y a quelques choses qui doivent être faites en plus de cela.

Tous les fichiers de classe dont Jetty a besoin pour démarrer devront être situés à la racine du fichier war lorsqu'il est empaqueté. Nous pouvons utiliser Ant pour le faire pour nous avant de <war> le fichier. Le fichier manifeste de la guerre aura également besoin d'un Main-Class attribut pour exécuter le serveur.

Voici une étape par étape:

Créez votre classe de serveur Jetty:

Ceci est adapté du lien que vous avez fourni.

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();
    }
}

Pour voir tout ce que vous pouvez configurer ici, jetez un œil à la documentation de l'API Jetty .

Construisez la guerre avec Ant:

Cela utilise un répertoire intermédiaire pour décompresser les fichiers de classe nécessaires dans la racine de la guerre afin qu'ils soient accessibles lorsque la guerre est exécutée.

<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>

Exécutez la guerre:

Si tout est correctement configuré ci-dessus, vous devriez pouvoir:

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
50
Rob Hruska

Ceci est une adaptation pour Maven de la réponse de @ RobHruska. Il copie simplement les fichiers de la classe principale et fusionne les fichiers Jetty JAR dans le fichier WAR, rien de nouveau, juste pour vous simplifier la vie si vous êtes nouveau - comme moi - à 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>
45
AhHatem

Nous avons compris cela en utilisant jetty-console-maven-plugin.

Chaque fois que vous exécutez le package mvn, il crée une autre guerre qui peut être utilisée avec Java -jar quepackage-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>

Il génère également les scripts init.d et tout pour vous!

14
Rafael Sanches

Hudson résout ce problème exact en utilisant le conteneur de servlets Winstone, qui prend directement en charge ce cas d'utilisation. http://winstone.sourceforge.net/#embedding

Peut-être que cela fonctionnerait pour vous?

Même si c'est un peu ancien, une autre alternative avec Jetty 8 consiste à simplement inclure les pots Jetty en tant que dépendances dans votre pom et à ajouter ce qui suit dans votre pom (par rapport à un script ant qui déballe la guerre et la reconditionne):

            <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>
6
Rodney Beede

Je suppose que "sans maven" vous voulez un pot que vous pouvez exécuter seul et non avec "mvn jetty: run" - pas que vous ne voulez pas du tout utiliser maven.

Il m'a fallu beaucoup de temps pour comprendre cela parce que j'ai trouvé de nombreuses options - aucune d'entre elles n'était très simple. Finalement, j'ai trouvé ce plugin maven de simplericity . Cela fonctionne à merveille.

3
schmmd

Ceci est mon exemple d'extrait ANT. L'idée est de décompresser les dépendances de Jetty puis de les inclure localement comme un fichier JAR normal:

<!-- 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>

Remarque:

Le répertoire WEB-INF/lib est destiné aux dépendances des applications Web. Dans ce cas, nous empaquetons le fichier WAR pour qu'il fonctionne comme le fichier Jetty JAR normal au démarrage

1
Mark O'Connor

J'ai déjà fait une chose similaire, mais lancez-vous l'application en tant que "Java -jar xxx.war"?. Vous n'avez que 2 pots et ça ne suffira pas je pense. Essayez également d'utiliser Jetty 7.0.0M1 (qui est la dernière version). Lorsque j'ai ajouté jetty-server et jetty-webapp en tant que deux dépendances (elles proviennent de org.Eclipse.jetty), j'obtiens les pots suivants dans le répertoire lib. Pour info, org.mortbay.jetty.Handler était dans le serveur de jetty * .jar.

  • jetty-continuation-7.0.0.M1.jar
  • jetty-http-7.0.0.M1.jar
  • jetty-io-7.0.0.M1.jar
  • jetty-security-7.0.0.M1.jar
  • jetty-server-7.0.0.M1.jar
  • jetty-servlet-7.0.0.M1.jar
  • jetty-util-7.0.0.M1.jar
  • jetty-webapp-7.0.0.M1.jar
  • jetty-xml-7.0.0.M1.jar
0
Kannan Ekanath
  • Mettre .jars dans une racine de fichier .war ne fait rien
  • Mettre des .jars à l'intérieur WEB-INF/lib n'aide pas la JVM à trouver les fichiers Jetty pour même commencer à lancer votre .war. Il est "trop ​​tard" pour les y mettre.
  • Mettre .jars dans le chemin de classe manifeste ne fonctionne que pour les fichiers .jar externes, pas ceux contenus dans le .jar

Alors que faire?

  • Utilisez un script de génération pour fusionner simplement tous les fichiers .jar dont vous avez besoin dans le fichier .war. Cela demande un peu de travail supplémentaire. C'est aussi un peu moche dans la mesure où le code compilé fait partie des fichiers servables dans le .war
  • Ajoutez des .jars dépendants au chemin de classe de la JVM avec "Java -cp jetty.jar: ... ...".
0
Sean Owen