我很难理解泽西的注射机制. JAX-RS规范( http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-520005)规定,可以在Application子类,根资源类和提供程序中通过@Context进行注入. 我现在有一个在启动时
我现在有一个在启动时实例化的类,并且有一个在每个请求上调用的方法.在方法内部,我需要访问当前的UriInfo对象.问题是,我的代码没有调用此方法.所以我无法直接将UriInfo传递给该方法.
我其实想做这样的事情:
public class MyClass implements ThirdPartyInterface { // not possible because class is no Application subclass, root resource class or provider @Context private UriInfo uriInfo; public void methodCallebByThirdPartyCode() { Uri requestUri = uriInfo.getRequestUri(); // do something } }
我试过这个.显然没有成功:
public class MyClass implements ThirdPartyInterface { private UriInfo uriInfo; public MyClass(UriInfo uriInfo) { this.uriInfo = uriInfo; } public void methodCallebByThirdPartyCode() { Uri requestUri = uriInfo.getRequestUri(); // do something } } @Provider @Produces(MediaType.WILDCARD) public class MyBodyWriter implements MessageBodyWriter<MyView> { @Context private UriInfo uriInfo; private MyClass myClass; private ThirdPartyClass thirdPartyClass; public MyBodyWriter() { // uriInfo is null at this time :( myClass = new MyClass(uriInfo); thirdPartyClass = new ThirdPartyClass(); thirdPartyClass.register(myClass); } public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException { // execute() calls MyClass#methodCallebByThirdPartyCode() thirdPartyClass.execute(); } }
我能想到的唯一解决方法就是这个.我不认为它很干净:
public class MyClass implements ThirdPartyInterface { private UriInfo uriInfo; public void setUriInfo(final UriInfo uriInfo) { this.uriInfo = uriInfo; } public void methodCallebByThirdPartyCode() { Uri requestUri = uriInfo.getRequestUri(); // do something } } @Provider @Produces(MediaType.WILDCARD) public class MyBodyWriter implements MessageBodyWriter<MyView> { @Context private UriInfo uriInfo; private MyClass myClass; private ThirdPartyClass thirdPartyClass; public MyBodyWriter() { myClass = new MyClass(); thirdPartyClass = new ThirdPartyClass(); thirdPartyClass.register(myClass); } public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException { myClass.setUriInfo(uriInfo); // execute() calls MyClass#methodCallebByThirdPartyCode() thirdPartyClass.execute(); myClass.setUriInfo(null); } }
我希望有更好的解决方案,但也许我完全走错了路.
谢谢!
迟到的回答,但是一个很好的问题…所以我们走吧:您可以使用org.glassfish.hk2.api.Factory和javax.inject.Provider进行注射.我不知道从哪个版本可用,所以也许你必须升级你的jersery版本.对于以下样品,我使用了汗布2.12.
首先,您必须为MyClass实现并注册/绑定Factory:
MyClassFactory:
import javax.inject.Inject; import javax.ws.rs.core.UriInfo; import org.glassfish.hk2.api.Factory; // ... public class MyClassFactory implements Factory<MyClass> { private final UriInfo uriInfo; // we will bind MyClassFactory per lookup later, so // the constructor will be called everytime we need the factory // meaning, uriInfo is also per lookup @Inject public MyClassFactory(final UriInfo uriInfo) { this.uriInfo = uriInfo; } @Override public MyClass provide() { return new MyClass(uriInfo) } @Override public void dispose(UriInfo uriInfo) { // ignore } }
通过ResourceConfig注册:
import org.glassfish.hk2.api.PerLookup; import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.glassfish.jersey.server.ResourceConfig; // ... public class MyResourceConfig extends ResourceConfig { public MyResourceConfig() { register(new AbstractBinder() { @Override protected void configure() { bindFactory(MyClassFactory.class).to(MyClass.class).in(PerLookup.class); // ... bind additional factories here } }); // ... } }
现在,您可以将每个查询的MyClass注入提供者,资源等.
但注意:Afaig有两种方法,只有一种方法最终会被视为提供者…
import javax.inject.Inject; import javax.ws.rs.Produces; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; // ... @Provider @Produces("application/foo-bar") public class MyBodyWriter implements MessageBodyWriter<MyView> { // first approache - don't do it! // will only injected once, cause MyBodyWriter is only instantiated once @Inject private MyClass myClass; // second approache - works fine! private final javax.inject.Provider<MyClass> provider; // MyBodyWriter instantiate once // get an inject provider here @Inject public MyBodyWriter(javax.inject.Provider<MyClass> myClassProvider) { this.provider = myClassProvider; } @Override public boolean isWriteable(Class<?> t, Type g, Annotation[] a, MediaType m) { return t == MyView.class; } @Override public long getSize(MyView t, Class<?> c, Type g, Annotation[] a, MediaType m) { // deprecated by JAX-RS 2.0 and ignored by Jersey runtime return 0; } @Override public void writeTo(MyView v, Class<?> c, Type t, Annotation[] a, MediaType m, MultivaluedMap<String, Object> s, OutputStream o) throws IOException, WebApplicationException { // attention: its not per lookup !!! MyClass myClassDirectInjected = myClass; System.out.println(myClassDirectInjected); // same instance everytime // but this is ;) MyClass myClassFromProvider = provider.get(); System.out.println(myClassFromProvider); // it's a new instance everytime // ... } }
希望这在某种程度上有所帮助.