Der Maven Loader ist eine Erweiterung des Tomcat Application Server um einen Maven Class-Path Loader. Damit können sogenannte Thin WAR Files deployed werden, also ein WAR-File das nur die eigentlichen Dateien enthält, Abhängigkeiten werden beim Deployment durch Maven nachgeladen und zum Class-Path hinzugefügt.

  • Ein Thin WAR kann durch das thin-war-maven-plugin erstellt werden.
  • Maven Loader ist kompatibel mit Tomcat 6 und Tomcat 7.
Laden Sie noch hoch oder deployen Sie schon?

Erklärung#

Bisher werden alle JARs in ein WAR-File nach /WEB-INF/lib eingepackt. Maven Loader löst dies nun anders und bietet volgende Vorteile:
  • Kleine WAR-Files: Kleine Web-Applications hätten eingentlich nur einige hundert Kilobytes, selbst größere Anwendungen überstiegen selten einige Megabyte, wären nicht die JAR-File in dem WAR-Archiv. In der Praxis findet man selten ein WAR-File unter 10 Megabyte, bei JEE-Anwendungen mit JSF, JPA und Spring ist man schnell bei 30 Megabyte. Kommen dann noch einige Drittbibliotheken dazu, kommt man schnell an die 100 Megabyte heran.
  • Deployment: Die WARs werden oft durch File-Upload auf den Application-Server gebracht. Selbst wenn sie direkt im Dateisystem oder über das lokale Netzwerk kopiert werden, sind 100 Megabyte dennoch eine große Datenmenge. Mit der eigentlichen Web-Anwendung werden wieder und wieder dieselben Daten übertragen. Auf dem Application-Server wird das WAR dann wieder ausgepackt, weil die enthaltenen JAR-Dateien sonst nicht in den Class-Path eingefügt werden können. Werden mehrere WAR-Dateien deployed, werden die enthaltenen JAR-Dateien unter umständen viele Male in unterschiedliche Deploy-Verzeichnisse kopiert. Das kostet Speicher und Zeit. Mit Maven Loader werden nur noch die Nutzdaten upgeloaded und deployed.
  • Build: Das bauen eines JAR-Files dauert nur wenige Augenblicke, weil es klein ist und nur die Dateien aus dem Projekt hineingepackt werden. Beim WAR-File geht das Compiling ebenso schnell, dann kommt das Packen der bereits gepackten JAR-Dateien, die Packer und CPU besonders intensiv beschäftigen. Und bei jedem Build dieselben Dateien. Mit Maven Loader werden nur noch die Projektdateien compiliert und eingepackt.
  • Maven: Inzwischen hat sich Maven beim Build durchgesetzt, weil es bequemer ist, den eigentlich Code oder das erzeugte Artifact frei von Dependencies zu halten. Wieso sollte Maven also nicht auch am Application Server die Dependencies nachladen?

Lösung#

Intersult Maven Loader ist eine Erweiterung des Tomcat Application Server, sodass dieser die Dependencies eines WAR-Files selbst laden kann. Maven Loader arbeitet dabei mit den settings.xml der Maven-Installation zusammen, sodass Proxy-Einträge oder Mirrors benutzt werden kännen. Dies ist gerade in Unternehmensanwendungen häufig der Fall.

Installation#

  1. Zunächst wird eine Tomcat-Instanz installiert. Das System ist bisher mit Tomcat 7 getestet, sollte auch mit Tomcat 6 lauffähig sein.
  2. Innerhalb der Tomcat-Installation (z.B. C:\Java\apache-tomcat-7.0.42\) wird das Verzeichnis "maven" aus dem Anhang ausgepackt.
  3. Die Datei <tomcat>/conf/catalina.properties wird editiert. Der Eintrag common.loader wird zusätzlich um ${catalina.home}/maven/*.jar erweitert.

Nun ist der Tomcat Maven-fähig!

Maven-WAR-Files#

Maven-WAR-Files (auch Thin-WAR-Files genannt) werden wie wie folgt aufgebaut:
  1. Es ist kein <war-file>/WEB-INF/lib enthalten.
  2. In <war-file>/META-INF/context.xml befindet sich die Datei context.xml(info).
  3. In <war-file>/META-INF/pom.xml befindet sich die POM-Datei mit dem das WAR-File gebaut worden ist.

Beim Deployment wird dadurch der Maven Loader aktiviert, der dann die POM-Datei des Projekts öffnet und die Dependencies zum Class-Path hinzufügt. Falls die Dependencies nicht im lokalen Repository sind, werden diese über das Aether-System von Maven heruntergeladen und lokal installiert.

Hinweis: In der erweiterten Tomcat-Instanz können weiterhin full blown WAR-Files installiert werden.

Build-Prozess#

Thin WARs sind normale WAR-Files, die statt der JAR-Dependencies ein pom.xml enthalten. Solche WAR-Files können daher auch selbst aufgebaut werden. Praktischer ist jedoch Maven dafür zu verwenden:
<project>
    ...
	<build>
	    ...
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.0</version>
				<executions>
					<execution>
						<id>compile</id>
						<goals>
							<goal>compile</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-resources-plugin</artifactId>
				<version>2.6</version>
				<executions>
					<execution>
						<id>copy-jsp</id>
						<phase>compile</phase>
						<goals>
							<goal>copy-resources</goal>
						</goals>
						<configuration>
							<resources>
								<resource>
									<directory>src/main/webapp</directory>
									<filtering>true</filtering>
								</resource>
							</resources>
							<outputDirectory>${project.build.directory}/${project.build.finalName}</outputDirectory>
						</configuration>
					</execution>
				</executions>
			</plugin>
			...
		</plugins>
		<extensions>
			<extension>
				<groupId>com.intersult</groupId>
				<artifactId>thin-war-maven-plugin</artifactId>
				<version>1.0<version>
			</extension>
		</extensions>
	</build>
	...
</project>

Erklärung: Das Compiler-Plugin und Resource-Plugin baut im Wesentlichen das Verzeichnis im Target auf, bevor das thin-war-maven-plugin das fertige WAR zusammensetzt. Das thin-war-maven-plugin ist dafür verantwortlich, die context.xml und die pom.xml an passender Stelle im WAR-File zu platzieren.

Lokal ausführen#

Es handelt sich nach wie vor um eine normales Maven-WAR-Projekt und ist mit dem tomcat6- bzw. tomcat7-maven-plugin ausführbar:
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
				<artifactId>tomcat7-maven-plugin</artifactId>
				<version>2.0</version>
				<configuration>
					<warSourceDirectory>${project.build.directory}/${project.build.finalName}</warSourceDirectory>
				</configuration>
			</plugin>

Das Ausführen erfolgt mit "mvn tomcat7:run" bzw. aus Eclipse heraus:

Maven Loader/maven tomcat7 plugin.PNG

Settings#

Für den Betrieb von Maven Loader ist keine Installation von Maven erforderlich, da diese embedded mitgeliefert wird. Es gibt zwei Möglichkeiten, Maven-Settings zu übergeben:
  • Maven-Installation: Wenn die Maven-Installation durch die Umgebungsvariable M2_HOME gesetzt ist, werden die ${M2_HOME}/conf/settings.xml verwendet.
  • Unabhängige Settings: Es können Settings für Maven von ${CATALINA_HOME}/conf/settings.xml geladen werden. Diese haben Priorität über die Maven-Installation.

Repository#

Durch die Settings kann das Repository eingestellt werden, in dem die heruntergeladenen Artifakte abgelegt werden. Es kann auch ein eigenes Repository für die Tomcat-Installation verwendet werden:
<settings>
    ...
    <localRepository>${CATALINA_HOME}/repository</localRepository>
    ...
</settings>

Ab Version 1.1 sind folgende System-Properties verfügbar:

  • maven.loader.debug: Damit wird das Debug-Logging von Maven aktiviert, um Probleme beim Dependency-Resolving leichter erkennen zu können.
  • maven.loader.scopes: Hier kann eine Komma-seperierte Liste von Maven-Scopes übergeben werden, die die Artifakte festlegen, die in den Classloader übernommen werden. Default-Wert ist "compile,runtime".

Downloads#

Der Maven-Loader kann aus dem Intersult Repository heruntergeladen werden: