Spring Boot War für Tomcat bereitgestellt


73

Ich versuche, eine Spring Boot-App für Tomcat bereitzustellen, da ich sie für AWS bereitstellen möchte. Ich habe eine WAR-Datei erstellt, die jedoch nicht auf Tomcat ausgeführt werden kann, obwohl sie sichtbar ist.

Details:
0. Hier ist meine App:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class App {
    public static void main(String[] args) {
        SpringApplication.run(SampleController.class, args);
    }
}

@Controller
@EnableAutoConfiguration
public class SampleController {
    @RequestMapping("/help")
    @ResponseBody
    String home() {
        String input = "Hi! Please use 'tag','check' and 'close' resources.";
        return input;
    }
}

application.properties hat Folgendes:

server.port=${port:7777}
  1. Nachdem ich einige Seiten und Fragen-Antworten gelesen hatte, fügte ich meinem POM Folgendes hinzu:

    http://maven.apache.org/xsd/maven-4.0.0.xsd "> 4.0.0

    <groupId>com.niewlabs</groupId>
    <artifactId>highlighter</artifactId>
    <version>1.0-SNAPSHOT</version>
    
    <packaging>war</packaging>
    
    <properties>
        <java.version>1.8</java.version>
    </properties>    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    

  2. Ich habe "mvn package" ausgeführt und eine WAR-Datei (Größe 250 MB) erhalten, die ich in den Ordner "webapps" gestellt habe.

  3. Ich habe Tomcat gestartet und kann meine App in meinem Fall "/highlighter-1.0-SNAPSHOT" aufgelistet sehen.
  4. Wenn Sie auf den Link für die App klicken, wird die Seite "Status 404" angezeigt.
  5. Wenn ich die Spring Boot-App alleine ausführe, ohne Container, läuft sie auf localhost: 7777, aber wenn ich sie in Tomcat ausführe, ist dort nichts.

Update: Es gibt noch eine andere Referenz . Ich bin mir nicht sicher, wie nützlich es ist.


4
Haben Sie SpringBootServletInitializerdie configureMethode erweitert und überschrieben ?
Andy Wilkinson

Nein, ich habe keine Erwähnung in den WAR-Anweisungen des Spring Guide gesehen. Können Sie mir bitte einen Link oder Details geben?
Daniil Shevelev

2
@ AndyWilkinson Danke für den Hinweis. Ich fand die Antwort im Spring Guide [ docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… . Aber meine App läuft immer noch nicht auf Tomcat.
Daniil Shevelev

Ich habe alle Schritte der Dokumente befolgt, aber trotzdem bekomme ich 404. Aus den Protokollen von tomcat localhost geht hervor, dass die Anwendung erkannt wurde. 09-Nov-2019 11:19:59.676 INFO [main] org.apache.catalina.core.ApplicationContext.log 1 Spring WebApplicationInitializers detected on classpath 09-Nov-2019 11:20:12.722 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: contextInitialized()
Ajay Yadav

Antworten:


106

In diesem Handbuch wird ausführlich erläutert, wie Sie die Spring Boot-App auf Tomcat bereitstellen:
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-create-a-deployable-war-file

Im Wesentlichen musste ich folgende Klasse hinzufügen:

public class WebInitializer extends SpringBootServletInitializer {   
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(App.class);
    }    
}

Außerdem habe ich POM folgende Eigenschaft hinzugefügt:

<properties>        
    <start-class>mypackage.App</start-class>
</properties>

7
Ich würde den Verweis auf den folgenden aktualisieren - docs.spring.io/spring-boot/docs/current/reference/htmlsingle/… Der Abschnitt "Glas in War Maven konvertieren" zeigt nur die eingebettete Version in Ihrer Referenz.
Trotzdem

Dieser Fix hat bei mir funktioniert! Ich kann bestätigen, dass die Dokumentation wie im obigen Kommentar vorgeschlagen aktualisiert wurde. docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
Miguel Reyes

2
Ich bin nicht sicher, ob das Hinzufügen der <start-class> -Eigenschaft erforderlich ist. Es wurde für meine Konfiguration nicht benötigt und wird in der Dokumentation, auf die verwiesen wird, nicht erwähnt.
LJ in NJ

Da die Anwendung in STS ohne diese "ServeletInitializer" -Datei ausgeführt wurde, entfernte ich diese Datei mit Ruhm und schlug mir 2 Tage lang den Kopf. Ich fragte mich, warum sie nicht auf Tomcat ausgeführt werden kann. Vielen Dank für diese Antwort. Beim Betrachten dieses Servlet-Namens erinnerte ich mich an meinen Fehler und nachdem ich diese Datei wieder ersetzt hatte, wurde er behoben.
Lerner

<Startklasse> wurde für mich nicht benötigt, da Spring Boot 2.1 ausgeführt wurde.
Agustí Sánchez

24

Hey, stellen Sie sicher, dass Sie diese Änderungen an der pom.xml vornehmen

<packaging>war</packaging>

Stellen Sie im Abschnitt "Abhängigkeiten" sicher, dass der Tomcat bereitgestellt wird, damit Sie das eingebettete Tomcat-Plugin nicht benötigen.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>       

    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <scope>provided</scope>
    </dependency>       

Das ist die ganze pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <start-class>com.example.Application</start-class>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>       

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>       

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

Und die Anwendungsklasse sollte so sein

Application.java

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

@SpringBootApplication
public class Application extends SpringBootServletInitializer {


    /**
     * Used when run as JAR
     */
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    /**
     * Used when run as WAR
     */
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(Application.class);
    }

}

Außerdem können Sie einen Controller zum Testen von MyController.java hinzufügen

package com.example;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyController {

    @RequestMapping("/hi")
    public @ResponseBody String hiThere(){
        return "hello world!";
    }
}

Anschließend können Sie das Projekt in einer Tomcat 8-Version ausführen und auf diese Weise auf den Controller zugreifen

http: // localhost: 8080 / demo / hi

Wenn Sie das Projekt aus irgendeinem Grund nicht zu Tomcat hinzufügen können, klicken Sie mit der rechten Maustaste in das Projekt und gehen Sie dann zu Erstellungspfad-> Erstellungspfad konfigurieren-> Projektflächen

Stellen Sie sicher, dass nur diese 3 ausgewählt sind

Dynamisches Webmodul 3.1 Java 1.8 Javascript 1.0


21

Ich denke, Sie sind hier durch verschiedene Paradigmen verwirrt. Erstens Kriegsdateien und Serverbereitstellung - diese Dinge gehören zur Java Enterprise Edition (Java EE). Diese Konzepte haben keinen wirklichen Platz in einer Spring-Boot-Anwendung, die einem anderen Modell folgt.

Spring-Boot ist dafür verantwortlich, einen eingebetteten Container zu erstellen und Ihre darin enthaltenen Dienste direkt aus Standard-JAR-Dateien auszuführen (obwohl es viel mehr kann). Ich denke, die Absicht dieses Modells ist es, die Entwicklung von Mikrodiensten zu unterstützen - wobei jeder Dienst seinen eigenen Container hat und vollständig in sich geschlossen ist. Sie können Ihren Code auch zum Generieren von Java EE-Apps verwenden, aber das wäre albern, wenn man bedenkt, dass Spring-Boot viel einfacher ist (für bestimmte Arten von Anwendungen / Diensten).

Angesichts dieser Informationen müssen Sie nun entscheiden, welchem ​​Paradigma Sie folgen möchten, und Sie müssen dem und nur dem folgen.

Spring-Boot ist ausführbar - Sie müssen nur die Hauptmethode in der App-Klasse ausführen, die Sie über die Befehlszeile oder mit Ihrer bevorzugten IDE oder Maven oder Gradle ausführen können (Tipp: Maven ist die richtige Antwort). Dadurch wird (standardmäßig) ein Tomcat-Server aufgerufen, auf dem Ihr Dienst verfügbar ist. In Anbetracht der Konfiguration, die Sie oben veröffentlicht haben, sollte Ihr Dienst verfügbar sein unter: http://localhost:7777/context/help- Der contextsoll durch Ihren Kontextnamen ersetzt werden, den Sie nicht freigegeben haben.

Sie sind nicht dazu gedacht, einen Krieg zu führen, Tomcat auszuführen oder irgendetwas einzusetzen. Nichts davon ist im Spring-Boot notwendig. Die Verpackung in Ihrem Pom sollte sein jar, nicht warund die scopeder spring-boot-starter-tomcatsollte entfernt werden - es ist sicherlich nicht vorgesehen.

Wenn Sie Ihre Hauptmethode ausführen, sollte die Konsolenausgabe den Kontext angeben, den Sie registriert haben. Verwenden Sie das, um die URL richtig zu machen.

Trotzdem muss Spring-Boot vorerst in einer JEE-Welt existieren (bis es weit verbreitet ist). Aus diesem Grund haben die Spring People einen Ansatz zum Aufbau eines Krieges anstelle eines ausführbaren JARs für die Bereitstellung in einem Servlet oder JEE-Container dokumentiert. Auf diese Weise kann ein Großteil der Spring-Boot-Technologie in Umgebungen eingesetzt werden, in denen es Einschränkungen gibt, alles andere als Kriege (oder Ohren) zu verwenden. Dies ist jedoch nur eine Antwort auf die Tatsache, dass solche Umgebungen weit verbreitet sind und nicht als notwendiger oder sogar wünschenswerter Teil der Lösung angesehen werden.


5
Ich würde gerne die Bereitstellung auf Tomcat vermeiden, aber es scheint die einfachste und einfachste Möglichkeit zu sein, meine App auf AWS bereitzustellen.
Daniil Shevelev

2
Nein, mit Spring-Boot und Docker - das ist der einfachste Weg, um überall bereitzustellen, einschließlich AWS (vertrau mir - ich spreche aus Erfahrung)
Software Engineer


4
Ich denke nicht, dass dies strukturell wahr ist. Mit Spring Boot können War-Dateien in einem Container bereitgestellt werden. Für den Großteil des Anwendungsfalls ist es jedoch richtig. Daher bin ich versucht, die Frage sowohl abzulehnen als auch zu bewerten. Siehe docs.spring.io/spring-boot/docs/current/reference/html/…
Wes

2
Wenn auf Tomcat bereits eine Reihe klassischer Spring-Anwendungen ausgeführt werden, ist die Bereitstellung von Spring Boot War-Dateien eine gute Möglichkeit, Spring Boot zu verwenden, ohne zu viel auf einmal zu ändern.
Jkerak

6

Ihre Application.javaKlasse sollte die SpringBootServletInitializerKlasse erweitern, z.

public class Application extends SpringBootServletInitializer {}

4

Lösung für Benutzer von Gradle

Plugin hinzufügen zu build.gradle

apply plugin: 'war'

Fügen Sie die bereitgestellte Abhängigkeit zu Tomcat hinzu

dependencies {
    // other dependencies
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}

3

Nachdem ich der Anleitung gefolgt war (oder Spring Initializr verwendet hatte), hatte ich eine WAR, die auf meinem lokalen Computer funktionierte, aber nicht remote funktionierte (auf Tomcat).

Es gab keine Fehlermeldung, es wurde nur "Spring Servlet Initialisierer wurde gefunden" angezeigt, aber es wurde überhaupt nichts unternommen.

17-Aug-2016 16:58:13.552 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.4
17-Aug-2016 16:58:13.593 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive /opt/tomcat/webapps/ROOT.war
17-Aug-2016 16:58:16.243 INFO [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.

und

17-Aug-2016 16:58:16.301 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log 2 Spring WebApplicationInitializers detected on classpath
17-Aug-2016 16:58:21.471 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log Initializing Spring embedded WebApplicationContext
17-Aug-2016 16:58:25.133 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log ContextListener: contextInitialized()
17-Aug-2016 16:58:25.133 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log SessionListener: contextInitialized()

Sonst ist nichts passiert. Spring Boot lief einfach nicht.

Anscheinend habe ich den Server mit Java 1.8 kompiliert und der Remotecomputer hatte Java 1.7.

Nach dem Kompilieren mit Java 1.7 begann es zu funktionieren.

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.7</java.version> <!-- added this line -->
    <start-class>myapp.SpringApplication</start-class>
</properties>

3

public class Application erweitert SpringBootServletInitializer {}

erweitert nur den SpringBootServletInitializer. Es funktioniert in Ihrem AWS / Tomcat


1
Können Sie klarstellen, was Ihre Antwort bringt, die weder in der Antwort 3 Stunden vor Ihrer noch in der akzeptierten Antwort aus dem Jahr 2015 behandelt wurde?
Foon

3

Ich hatte das gleiche Problem und finde eine Lösung, indem ich dieser Anleitung folge . Ich laufe mit Ziel in Maven.

sauberes Paket

Es hat bei mir funktioniert, Thanq


1

Update 2018-02-03 mit Spring Boot 1.5.8.RELEASE.

In pom.xml müssen Sie dem Spring-Plugin beim Erstellen mitteilen, dass es sich um eine Kriegsdatei handelt, indem Sie das Paket wie folgt in Krieg ändern:

<packaging>war</packaging>

Außerdem müssen Sie den eingebetteten Kater beim Erstellen des Pakets ausschließen, indem Sie Folgendes hinzufügen:

    <!-- to deploy as a war in tomcat -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>

Das vollständige ausführbare Beispiel finden Sie hier https://www.surasint.com/spring-boot-create-war-for-tomcat/


3
Das reicht nicht aus. Die Hauptanwendungsklasse muss SpringBootServletInitializer implementieren, um sowohl für die Container- als auch für die eigenständige Ausführung kompatibel zu sein. Dem Beispiel des Op fehlt es.
Aram Paronikyan

0

Wenn es Ihr Ziel ist Ihre Spring - Boot - Anwendung auf AWS bereitstellen , Boxfuse bietet Ihnen eine sehr einfache Lösung.

Alles was Sie tun müssen ist:

boxfuse run my-spring-boot-app-1.0.jar -env=prod

Dieser Wille:

  • Verschmelzen Sie ein minimales Betriebssystem-Image, das auf Ihre App zugeschnitten ist (etwa 100-mal kleiner als eine typische Linux-Distribution).
  • Übertragen Sie es in ein sicheres Online-Repository
  • Wandeln Sie es in ca. 30 Sekunden in ein AMI um
  • Erstellen und konfigurieren Sie eine neue elastische IP oder ELB
  • Weisen Sie ihm einen neuen Domainnamen zu
  • Starten Sie eine oder mehrere Instanzen basierend auf Ihrem neuen AMI

Alle Bilder werden in Sekunden generiert und sind unveränderlich. Sie können unverändert auf VirtualBox (dev) und AWS (test & prod) ausgeführt werden.

Alle Aktualisierungen werden als blau / grüne Bereitstellungen ohne Ausfallzeit ausgeführt. Sie können die automatische Skalierung auch mit nur einem Befehl aktivieren.

Boxfuse versteht auch, dass Ihre Spring Boot-Konfiguration automatisch Sicherheitsgruppen und ELB-application.properties Integritätsprüfungen basierend auf Ihrer Konfiguration konfiguriert .

Hier ist ein Tutorial, das Ihnen den Einstieg erleichtert: https://boxfuse.com/getstarted/springboot

Haftungsausschluss: Ich bin der Gründer und CEO von Boxfuse


0

Wenn Sie eine neue App erstellen, anstatt eine vorhandene zu konvertieren, können Sie WAR-basierte Spring-Boot-Anwendungen am einfachsten über Spring Initializr erstellen .

Die Anwendung wird automatisch für Sie generiert. Standardmäßig wird Jar erstellt. In den erweiterten Optionen können Sie jedoch WAR erstellen. Dieser Krieg kann auch direkt ausgeführt werden.

Geben Sie hier die Bildbeschreibung ein

Noch einfacher ist es, das Projekt direkt aus IntelliJ IDEA zu erstellen:

Datei → Neues Projekt → Spring Initializr

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.