Run java web apps in embedded containers with Maven, Jetty and Tomcat

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ⭐🙏
While developing java web applications is very practical to have quick feedback from a “real” environment. In this post I’ll explore how to run a java web application with Maven in an embedded container be it Jetty or Tomcat. I’ll show how I have configured them for the development of podcastpedia project backing the Podcastpedia.org website.
Source code for this post is available on Github - podcastpedia.org is an open source project.
Prerequisites
You should have Maven and at least Java 7 installed. Ideally you could setup up the podcastpedia project yourself to see it in action.
Jetty Maven Plugin
<!-- https://www.eclipse.org/jetty/documentation/current/jetty-maven-plugin.html --> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>${jetty.version}</version> <configuration> <jettyConfig>${project.basedir}/src/main/resources/config/jetty9.xml</jettyConfig> <stopKey>STOP</stopKey> <stopPort>9999</stopPort> <scanIntervalSeconds>5</scanIntervalSeconds> <scanTargets> <scanTarget>${project.basedir}/src/main</scanTarget> <scanTarget>${project.basedir}/src/test</scanTarget> </scanTargets> <contextXml>${project.basedir}/src/test/resources/jetty-context.xml</contextXml> <webAppConfig> <contextPath>/</contextPath> </webAppConfig> </configuration> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.connector.java.version}</version> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>${java.mail.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> <version>${tomcat.jdbc.version}</version> </dependency> </dependencies> </plugin>
Notes:
- jettyConfig points to the Jetty configuration file; see next section for more explanations
- defined folders (scanTargets) where Jetty looks for changes every 5 seconds (scanInterval)
- defined external dependencies to connect to database and send email
Jetty.xml configuration file
<?xml version="1.0" encoding="UTF-8"?> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <New id="pcmdbDS" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg>jdbc/pcmDB</Arg> <Arg> <New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"> <Set name="Url">jdbc:mysql://localhost:3307/pcmDB?allowMultiQueries=true </Set> <Set name="User">pcm</Set> <Set name="Password">pcm_pw</Set> </New> </Arg> </New> <New id="mailSessionId" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg>mail/Session</Arg> <Arg> <New class="org.eclipse.jetty.jndi.factories.MailSessionReference"> <Set name="user">test-dev@podcastpedia.org</Set> <Set name="password">test-dev</Set> <Set name="properties"> <New class="java.util.Properties"> <Put name="mail.host">mail.podcastpedia.org</Put> <Put name="mail.debug">true</Put> <Put name="mail.transport.protocol">smtp</Put> <Put name="mail.smtp.port">25</Put> <Put name="mail.smtp.auth">true</Put> </New> </Set> </New> </Arg> </New> </Configure>
In the Jetty configuration file (jetty.xml) you have the following configured:
- The Server class (or subclass if extended) and global options.
- A ThreadPool (min and max thread).
- Connectors (ports, timeouts, buffer sizes, protocol).
- The handler structure (default handlers and/or a contextHandlerCollections).
- The deployment manager that scans for and deploys webapps and contexts.
- Login services that provide authentication checking.
- A request log.
Apache Tomcat Maven Plugin
<!-- https://tomcat.apache.org/maven-plugin-trunk/index.html --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <!-- http port --> <port>8080</port> <!-- application path always starts with /--> <path>/</path> <!-- optional path to a context file --> <contextFile>context.xml</contextFile> <!-- optional system propoerties you want to add --> <systemProperties> <appserver.base>${project.build.directory}/appserver-base</appserver.base> <appserver.home>${project.build.directory}/appserver-home</appserver.home> <derby.system.home>${project.build.directory}/appserver-base/logs</derby.system.home> <java.io.tmpdir>${project.build.directory}</java.io.tmpdir> </systemProperties> <!-- if you want to use test dependencies rather than only runtime --> <useTestClasspath>false</useTestClasspath> <!-- optional if you want to add some extra directories into the classloader --> <additionalClasspathDirs> <additionalClasspathDir></additionalClasspathDir> </additionalClasspathDirs> </configuration> <!-- For any extra dependencies needed when running embedded Tomcat (not WAR dependencies) add them below --> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.connector.java.version}</version> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>${java.mail.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> <version>${tomcat.jdbc.version}</version> </dependency> </dependencies> </plugin>
Notes
- specify port where Tomcat runs
- specify contextFile where Tomcat looks for configuration
- defined external dependencies to connect to database and send email
Context.xml
<Context> <Resource name="jdbc/pcmDB" auth="Container" type="javax.sql.DataSource" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" initialSize="5" maxActive="55" maxIdle="21" minIdle="13" timeBetweenEvictionRunsMillis="34000" minEvictableIdleTimeMillis="55000" validationQuery="SELECT 1" validationInterval="34" testOnBorrow="true" removeAbandoned="true" removeAbandonedTimeout="233" username="pcm" password="pcm_pw" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3307/pcmDB?allowMultiQueries=true" /> <Resource name="mail/Session" auth="Container" type="javax.mail.Session" username="test-dev@podcastpedia.org" password="test-dev" mail.smtp.host="mail.podcastpedia.org" mail.smtp.port="25" mail.smtp.user="test-dev@podcastpedia.org" mail.transport.protocol="smtp" mail.smtp.auth="true" /> </Context>
In context.xml there are defined the database and email resources.
Note:
These are simple configurations, but suffice for current development. My advice is to read the corresponding documentation for more advanced options and capabilities.
There you go… Java webapps powered by Spring Framework running light servlet containers posing a true alternative to JAVA EE servers and all the costs that come with them.
Source code for this post is available on Github - podcastpedia.org is an open source project.