Pregunta

This is a question about better separating the code for embedding jetty from the code for wiring up servlets.

I am trying to adapt this sample code such that I will be getting a runnable war, i.e. a war file that I can drop into an existing Jetty container, or run standalone using a command like java -jar webapp-runnable.war. The sample code belongs to these two blog posts: No.1, No.2.

I followed the GuiceServlet manual and created a web.xml and GuiceServletContextListener (see below), but they don't seem to get me very far with mvn jetty:run; When I try to run mvn jetty:run, I get the following error:

[main] DEBUG org.eclipse.jetty.util.log - Logging to Logger[org.eclipse.jetty.util.log] via org.eclipse.jetty.util.log.Slf4jLog
WARN:oejw.WebAppContext:main: Failed startup of context o.e.j.m.p.JettyWebAppContext@3cceafcb{/,file:/[...]/src/main/webapp/,STARTING}{file:/[...]/src/main/webapp/}
com.google.inject.ConfigurationException: Guice configuration errors:||1) Explicit bindings are required and com.google.inject.servlet.InternalServletModule$BackwardsCompatibleServletContextProvider is not explicitly bound.|  while locating com.google.inject.servlet.InternalServletModule$BackwardsCompatibleServletContextProvider||1 error
    at [stack strace clipped]

Here's my code. As mentioned before, I started with this repo on github.

1) I extracted the anonymous inner class of type AbstractModule from com.teamlazerbeez.http.HttpServerMain and put it into a new class com.teamlazerbeez.http.HttpServerModule. This class is now instantiated when creating the Guice Injector in HttpServerMain (l36).

2) My web.xml:

<?xml version="1.0" ?>
<web-app
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    metadata-complete="false"
    version="3.0">

    <filter>
        <filter-name>guiceFilter</filter-name>
        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>guiceFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <listener>
        <listener-class>com.teamlazerbeez.http.GuiceServletConfig</listener-class>
    </listener>
</web-app>

3) My com.teamlazerbeez.http.GuiceServletConfig:

public class GuiceServletConfig extends GuiceServletContextListener {

    @Override
    protected Injector getInjector() {
        //I know this code not come close to doing what I want, but I just don't know where to start
        return Guice.createInjector(new HttpServerModule());
    }

}

My question: How can I refactor the HttpServerMain main method and HttpServerModule in such a way that the setup process described by them becomes usable to my GuiceServletConfig? And what must GuiceServletConfig look like for this to work?

¿Fue útil?

Solución

I never got a war working as jar, so I always go for one of the two solutions. However, when using a war, its not hard to setup a embedded Jetty server that works in your IDE. To do that you can use a WebAppContext to set it up using a web.xml. See this documentation for an example. From there, everything should work as advocated on the Guice site.

However, this will not create a runnable war (like java -jar yourapp.war) because jars have a different internal layout. However, if you want to you can use the jetty-runner to fix this using java -jar jetty-runner.jar yourapp.war.

Otros consejos

I took @Alex's advice and forget about creating a standalone-runnable war, and instead focused on creating just a war that does most of the wiring up in a guice ServletModule.

For this purpose, I changed my HttpServerModule to extend a ServletModule (instead of AbstractModule) and put most of the HttpServerMain.main() logic in its configureServlets() method:

public class HttpServerModule extends ServletModule {
    @Override
    protected void configureServlets() {
        MetricRegistry metricRegistry = new MetricRegistry();
        bind(MetricRegistry.class).toInstance(metricRegistry);

        install(new SandwichModule());
        install(new JerseyMetricsModule());

        JmxReporter reporter = JmxReporter.forRegistry(metricRegistry).build();
        reporter.start();
    }
}

You'll notice that some of the HttpServerMain.main() logic does not appear in java code any more now. This is because the web.xml takes care of these things now.

My web.xml and GuiceServletConfig remain unchanged, and I can now run this using the mvn jetty:run command. The HttpServerMain can now be deleted, as it does not do anything useful any more.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top