Software Developers
Showing results for 
Search instead for 
Do you mean 

Embedding Jetty in a Java Main Application

amirkibbar on ‎06-20-2013 12:26 AM

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.

 

 

About the Author

amirkibbar

Comments
Thai Dang Vu
on ‎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
on ‎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.
Events
Jun 7-9
Las Vegas
Discover 2016 Las Vegas
Discover 2016 in Las Vegas, the ultimate showcase technology event for business and IT professionals to learn, connect, and grow.
Read more
Each Month in 2016
Online
Software Expert Days - 2016
Join us online to talk directly with our Software experts during online Expert Days. Find information here about past, current, and upcoming Expert Da...
Read more
View all