Maven und Jetty Embedded

Ich war auf der Suche nach einem Applikationsserver oder Servletcontainer, den ich embedded laufen lassen kann. Ziel ist es, eine quasi Standalone-Webanwendung hinzubekommen, die keinen installierten Applikationsserver benötigt. Am Ende sollte ein java -jar anwendungs.jar reichen, um eine Webanwendung zu starten. Ich hab Jetty ausprobiert.

Um Jetty als embedded Servletcontainer laufen lassen zu können, habe ich folgende pom.xml zusammengestellt:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.yellowshoes.jettyembedded</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>test</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>9.1.5.v20140505</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>de.yellowshoes.jettyembedded.test.HelloWorld</mainClass>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>de.yellowshoes.jettyembedded.test.HelloWorld</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Noch kurz die wichtigsten Teile der pom.xml erklärt.

Damit werden die notwendigen Jar-Dateien von Jetty als Abhängigkeiten für das Projekt definiert:

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>9.1.5.v20140505</version>
        </dependency>

Mit dem exec-maven-plugin kann man per Maven eine beliebige Javaklasse (wenn sie denn eine main-Methode implementiert) über Maven Kommandozeile aufrufen. Im Beispiel wird versucht eine Klasse de.yellowshoes.jettyembedded.test.HelloWorld aufzurufen. Der Aufruf über die Kommandozeile sieht dann beispielsweise so aus: mvn clean compile exec:java

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>de.yellowshoes.jettyembedded.test.HelloWorld</mainClass>
                </configuration>
            </plugin>

Um ein Standalone-Jar zu erzeugen, nutze ich hier das Share-Plugin. Damit wird das Jar gebaut und alle definierten Abhängigkeiten entpackt und mit ins erzeugte Jar eingefügt. Der Aufruf zum Bauen des Jar sieht so aus: mvn clean install

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>de.yellowshoes.jettyembedded.test.HelloWorld</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

Die erzeugte Jar-Datei sollte jetzt test-0.0.1-SNAPSHOT.jar heissen und mittels java -jar test-0.0.1-SNAPSHOT.jar gestartet werden können….wenn man die fehlende Klasse HelloWorld hätte 🙂

package de.yellowshoes.jettyembedded.test;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;

public class HelloWorld extends AbstractHandler {

    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        response.setContentType("text/html;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        baseRequest.setHandled(true);
        response.getWriter().println("<h1>Hello World</h1>");
    }

    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        server.setHandler(new HelloWorld());

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