Embedding Jetty in a Java Main Application

There are several optional solutions for this problem:

  1. Use Java SE's own internal HTTP server together with Spring's SimpleHttpServerFactoryBean
  2. Use Winstone lightweight servlet container the way Jenkins CI uses it
  3. Embed Jetty and programmatically configure it to start any servlet

Option 1 - Java SE internal HTTP Server

The advantage of this option is that it is the most simple to start and use. Here's an example of how to start it to export some Spring bean as a network service using HttpIvoker (one of Spring Remoting's transport means):

<bean name="accountExporter" 
    class="org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter">
    <property name="service" ref="accountService"/>
    <property name="serviceInterface" value="example.AccountService"/>
</bean>

<bean id="httpServer" 
        class="org.springframework.remoting.support.SimpleHttpServerFactoryBean">
    <property name="contexts">
        <util:map>
            <entry key="/remoting/AccountService" value-ref="accountExporter"/>
        </util:map>
    </property>
    <property name="port" value="8080" />
</bean>

 As you can see this creates an HTTP server that listens to port 8080 and exposes the service at /remoting/AccountService. There is , however, a major disadvantages to this option - it is far from being robust - the internal HttpServer is not really "production ready" - as I see it, this server is intended to be easy to configure to be used for demos or tests.

 

Option 2 - Winstone Lightweight Servlet Container

Winstone is a really lightweight servlet container - its jar is only 166Kb. Jenkins CI uses Winstone as an internal servlet container if you don't want to install Jenkins in an application server. This option is perfectly valid, but requires some hacking around bootstrapping. Jenkins CI wrote a special class loader that starts Winstone and tells it where to find the war file in which it actually resides. Another disadvantage of this option is that Winstone seems (to me) to be a dead project - the last version of it was released on January 22nd 2008 and there's seems to be not much traffic in its sourceforge site, and no plans to support servlet 3.0 (it currently only supports servlet 2.5).

 

Option 3 - Embedding Jetty

So we're left with embedding Jetty. This requires a bit more work than option 1, but you will end up with a fully functional web container that is in continuous development, that is robust and that support servlet 3.0.

Here's how it's done in 3 easy steps:

  • Add the relevant Jetty dependencies to your project
  • Configure Jetty programmatically - add your servlet
  • Start Jetty

Required Jetty Dependencies - I used version 8.1.4 of Jetty:

<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-server</artifactId>
    <version>8.1.4.v20120524</version>
</dependency>

<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-servlet</artifactId>
    <version>8.1.4.v20120524</version>
</dependency>

But I'm pretty sure this will work exactly the same with Jetty 7.x (not with 6.x though because the internal API has changed significantly).

 

Configuring Jetty Programmatically (and Starting it)

Create a new select channel connector - this creates the HTTP and HTTPS connectors, as well as sets the number of threads the container will use:

SelectChannelConnector connector = new SelectChannelConnector();
connector.setMaxIdleTime(1000);
connector.setAcceptors(10);
connector.setPort(8080);
connector.setConfidentialPort(8443);

 Create the server and assign the connectors to it:

server = new Server();
server.setConnectors(new Connector[]{connector});

 Register our servlet and bind it to an application context (the "web application" name):

ServletContextHandler handler = new ServletContextHandler(server, "/context", true, false);

ServletHolder servletHolder = new ServletHolder("foo", MyServlet.class);

 Add the servlet to the handler and start the server:

handler.addServlet(servletHolder, "/foo");
server.start();

 

 

All together now:

SelectChannelConnector connector = new SelectChannelConnector();
connector.setMaxIdleTime(1000);
connector.setAcceptors(10);
connector.setPort(8080);
connector.setConfidentialPort(8443);

server = new Server();
server.setConnectors(new Connector[]{connector});

ServletContextHandler handler = new ServletContextHandler(server, "/context", true, false);

ServletHolder servletHolder = new ServletHolder("foo", MyServlet.class);

handler.addServlet(servletHolder, "/foo");

server.start();

 

The above example will result in a Jetty listening to ports 8080, 8443 with 10 threads and a 1 second idle time (1000 milliseconds) with a single "application" registered in it and a single servlet at the following address: /context/foo.

 

That's great, but we want more - what we really want is to hook our "web application" to Spring MVC. This is how that's done - instead of registering MyServlet we'll register DispatcherServlet and tell it where to find its spring context by using a regular servlet context init param:

ServletHolder servletHolder = new ServletHolder("rest", DispatcherServlet.class);
servletHolder.setInitParameter("contextConfigLocation", "classpath:META-INF/spring/standalone/rest-servlet.xml");

handler.addServlet(servletHolder, "/rest/*");

 

As you can see the DispatcherServlet will look for its Spring context in the classpath in META-INF/spring/standalone/rest-servlet.xml and also all URIs that start with /context/rest will be passed to the DispatcherServlet for processing. From here on it's just regular Spring MVC, no special thing about it - Spring MVC is completely unaware that it is running in an embedded container that was programmatically configured.

 

 

Comments
Thai Dang Vu(anon) | ‎06-20-2013 03:04 PM

Could you go a little bit further by telling where I can place all the .js, .html and .jsp files?

 

Thank you.

amirkibbar | ‎07-15-2013 08:40 AM

Thai, the location of the web resources depends on the content of your rest-servlet.xml. In general you can place them in the root of your class path in some jar and access them with getResourceAsStream. If you need JSP/JSTL then you need to setup your Spring MVC InternalResourceViewResolver to point to whereever you placed these resources

Leave a Comment

We encourage you to share your comments on this post. Comments are moderated and will be reviewed
and posted as promptly as possible during regular business hours

To ensure your comment is published, be sure to follow the Community Guidelines.

Be sure to enter a unique name. You can't reuse a name that's already in use.
Be sure to enter a unique email address. You can't reuse an email address that's already in use.
Type the characters you see in the picture above.Type the words you hear.
Search
About the Author


Follow Us
The opinions expressed above are the personal opinions of the authors, not of HP. By using this site, you accept the Terms of Use and Rules of Participation