JAX-WS and Guice 3

2020-07-23 03:03发布

问题:

Is there some way to take SOAP web service classes creates with JAX-WS and inject them with, say, Guice 3.0 (guice-persist) transactions or even just plain ol' dependency injection? The guiceyfruit package provided a @GuiceManaged annotation that made this possible with Guice 2.0, but guiceyfruit (from my testing) appears to be incompatible with Guice 3, and I don't think the project is active any longer.

Perhaps because there is another way of doing this? Maybe a JSR standard way?

回答1:

I came across this same issue a while back and I had a look at the Guicyfruit code and decided to extract what I needed. This resulted in three classes.

First we need an annotation that we can use to annotate our web service endpoint with.

GuiceManaged.java

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.xml.ws.spi.WebServiceFeatureAnnotation;
import com.google.inject.Module;
import com.sun.xml.ws.api.server.InstanceResolverAnnotation;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@WebServiceFeatureAnnotation(id = GuiceManagedFeature.ID, bean = GuiceManagedFeature.class)
@InstanceResolverAnnotation(GuiceManagedInstanceResolver.class)
public @interface GuiceManaged {
    Class<? extends Module>[] modules();
}

Second we need the GuiceManagedFeature mentioned in the annotation above.

GuiceManagedFeature.java

import javax.xml.ws.WebServiceFeature;
import com.sun.xml.ws.api.FeatureConstructor;

public class GuiceManagedFeature extends WebServiceFeature {

    public static final String ID = "any.string.will.do.here";

    @FeatureConstructor
    public GuiceManagedFeature() {
        this.enabled = true;
    }

    @Override
    public String getID() {
        return ID;
    }
}

And third we create the actual resolver.

GuiceManagedInstanceResolver.java

import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.WebServiceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.server.WSEndpoint;
import com.sun.xml.ws.api.server.WSWebServiceContext;
import com.sun.xml.ws.server.AbstractMultiInstanceResolver;

public class GuiceManagedInstanceResolver<T> extends AbstractMultiInstanceResolver<T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(GuiceManagedInstanceResolver.class);

    private static Injector injector;

    private transient WSWebServiceContext webServiceContext;

    public GuiceManagedInstanceResolver(final Class<T> clazz) {
        super(clazz);
    }

    @Override
    public T resolve(final Packet request) {
        final T instance = injector.getInstance(this.clazz);
        injector.injectMembers(instance);

        return instance;
    }

    @SuppressWarnings("rawtypes")
    @Override
    public void start(final WSWebServiceContext wsWebServiceContext, final WSEndpoint endpoint) {
        super.start(wsWebServiceContext, endpoint);
        this.webServiceContext = wsWebServiceContext;

        synchronized (GuiceManagedInstanceResolver.class) {
            if (injector == null) {
                final List<Module> moduleInstances = new ArrayList<Module>();
                final Class<? extends Module>[] modules = this.clazz.getAnnotation(GuiceManaged.class).modules();

                for (final Class<? extends Module> moduleClass : modules) {
                    try {
                        moduleInstances.add(moduleClass.newInstance());
                    } catch (final InstantiationException exception) {
                        LOGGER.error("Could not instantiate guice module [{}]", moduleClass.getName());
                    } catch (final IllegalAccessException e) {
                        LOGGER.error("Could not instantiate guice module [{}]", moduleClass.getName());
                    }
                }

                moduleInstances.add(new AbstractModule() {
                    @Override
                    protected void configure() {
                        this.bind(WebServiceContext.class).toInstance(GuiceManagedInstanceResolver.this.webServiceContext);
                    }
                });

                injector = Guice.createInjector(moduleInstances);
            }
        }
    }
}

The above example uses SLF4J for logging but it's of course up to you to use whatever you wish.



回答2:

Got some errors in my logs related to guicyfruit calling 2.0 internals that no longer exist in 3.0. From the GuiceManaged code, it is actually just one guicyfruit call that is made so I decided to rip out the dependency and look around for alternatives.

There is a fork at http://code.google.com/p/guice-recipes/ which may or may not solve the issue if used instead of guicyfruit.

I went with the http://code.google.com/p/google-guice/issues/detail?id=288#c69 code and used it as my new dispose() method in GuiceManagedInstanceResolver.

I have working Guice injections and aspects within my code now, and no log output related to missing methods and/or memory leaks.



标签: jax-ws guice