Publishing JAX-WS Webservice with Guice in a Servl

2019-02-25 20:22发布

问题:

We are currently porting an existing JBoss EJB application to a pure servlet solution which is supposed to run in a Jetty (we're currently using version 6, but the version is mostly irrelevant) and which uses Guice for dependency injection and AOP. Despite the huge complexity we've been quite succesfully so far. The persistence layer and most of our services are up and running, including JAX-RS REST services.

However, when we started porting our existing JAX-WS SOAP services we ran into difficulties. We already spent about a day searching the web and it seems that many people ran into the same issues years ago. However, nobody seems to offer a good solution.

More details about our architecture

We're using a GuiceServletContextListener to create our global Injector which is configured with all the modules. It is vital that we only have one Injector because we need to support singletons.

As far as we know, the concrete JAX-WS implementation is not relevant. We're currently experimenting with Metro, but we could probably just as well use Apache-CXF.

Approaches evaluated so far

This stackoverflow post suggests creating the service manually and then publishing it through Endpoint.publish(...). However, this is not an acceptable solution, because it does not use the Jetty container, but starts its own HTTP server.

final Module module = new HelloModule();
final Injector injector = Guice.createInjector(module);
final HelloService helloService = injector.getInstance(HelloService.class);
Endpoint.publish("http://localhost:8080/helloService", helloService);

The same stackoverflow post also suggests using JAX-WS Guice integration which in general sounds like a good approach. However, this solution creates its own Injector and is therefore incompatible with our GuiceServletContextListener based approach. We found this thread where exactly the same problem is discussed, but nobody seems to have a solution.

We also looked at guice-cxf which is supposed to make the integration of Apache-CXF into Guice applications easy, but as far as we understand the description, this only works for JAX-RS REST services so far.

To not waste any more time on this and trying to reinvent the wheel we posted this question here in the hope that someone else has already been through this hell and can give us some pointers or maybe even some working examples. Any help is greatly appreciated.

回答1:

We finally solved it quite elegantly by extending CXFNonSpringServlet. You simply override the loadBus() method where you can configure all your service endpoints.

@Singleton
public class SoapServlet extends CXFNonSpringServlet {
    private static final long serialVersionUID = 1L;

    private final SomeFacade someFacade;

    @Inject
    SoapMachineServlet(final SomeFacade someFacade) {
        this.someFacade = someFacade;
    }

    @Override
    public void loadBus(ServletConfig servletConfig) throws ServletException {
        super.loadBus(servletConfig);

        Bus bus = getBus();
        BusFactory.setDefaultBus(bus);
        Endpoint.publish("/SomeFacade", someFacade);
    }
}

The class itself is a simply a servlet, which can then be bound using a ServletModule:

public class SomeModule extends ServletModule {
    @Override
    protected void configureServlets() {
        serve("/some/path*").with(SoapServlet.class);
    }
}