Introduction
As you may already know, creating a war archive and deploying it on a preinstalled Servlet Container is not the only way running a Java webapp, since you can also embed the Web-Server in the application itself. Sometimes such artifacts are delivered as standalone executable programs that can be easily started and stopped in the commandline and even run as a service in the background. Maybe you should also consider producing your app this way and benefit from its huge advantages:- No preinstalled Webserver/Servlet Container required that would take additional maintenance.
- Easy Cross-Platform. Same artifact can of course be run on any System.
- Complete Standalone Software
Embedded Tomcat
In my tutorial ill use an embedded Tomcat as a Servlet Container. So we want to add the Maven dependencies first.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!-- embedded Tomcat --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>7.0.37</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-logging-log4j</artifactId> <version>7.0.37</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>7.0.37</version> </dependency> |
We can use them now to create a StartServer class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public final class StartServer { private StartServer() { } public static void main(String[] args) throws Exception { // We will set the basedir Systemproperty accordingly when running the Program // Actually the mavenplugin appassembler will do this for us String basedir = System.getProperty("basedir"); String webappLocation = new File(basedir + "/webapp").getAbsolutePath(); int port = 8080; Tomcat tomcat = new Tomcat(); tomcat.setPort(port); tomcat.addWebapp("/", webappLocation); tomcat.start(); tomcat.getServer().await(); } } |
Exploded War
Now we need to make an exploded war in our "target" directory. I choose to create a folder inside "target" that holds the application as a whole including bin files, configuration and the webapp itself. This makes it easy to transport the complete app to another machine.- src/...
- target/myapp/bin
- target/myapp/conf
- target/myapp/webapp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <executions> <execution> <id>war-exploded</id> <phase>package</phase> <goals> <goal>exploded</goal> </goals> <configuration> <webappDirectory>${project.build.directory}/myapp/webapp</webappDirectory> <archiveClasses>true</archiveClasses> </configuration> </execution> </executions> </plugin> |
If you run mvn clean package right now you should get your webapp compiled into target/myapp/webapp
Startup Scripts
Finally we need startup Scripts to actually run our application. We need a shell script for unix Systems and a bat file for Windows. The Appassembler maven plugin comes in handy here. It is a very thoughtout plugin that creates exactly what we need and even sets the basedir Systemproperty. I'll configure it to use our exploded webapp and StartServer class.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>appassembler-maven-plugin</artifactId> <version>1.3</version> <configuration> <assembleDirectory>${project.build.directory}/myapp</assembleDirectory> <repositoryLayout>flat</repositoryLayout> <repositoryName>webapp/WEB-INF/lib</repositoryName> <generateRepository>false</generateRepository> <copyConfigurationDirectory>true</copyConfigurationDirectory> <configurationDirectory>conf</configurationDirectory> <programs> <program> <mainClass>com.myapp.StartServer</mainClass> <name>myapp</name> </program> </programs> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>assemble</goal> </goals> </execution> </executions> </plugin> |
Done. Appassembler now creates executable scripts for all platforms inside the target/myapp/bin directory. You could even put configuration files into src/main/config that would be copied into target/myapp/conf automatically by the plugin.
Result
If we run mvn clean package now we get a completely transportable standalone webapp in our target directory!