JAX-WS and Guice 3
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?
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.
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.
精彩评论