如何将对象注入jersey请求上下文?
我有这种情况下,我想写一个filter,我希望这个filter插入一些对象到当前的请求,并传递它,以便当资源类获取请求时,它可以使用该对象。
过滤类
@Override public void filter(ContainerRequestContext request) throws IOException { MyObject obj = new MyObject(); // Inject MyObject to request which I dont know how }
资源类
@PUT @Consumes("application/json") @Path("/") public String create( JSONParam sample, @Context MyObject obj) { System.out.println(obj.getName()); return ""; }
你可以使用ContainterRequestContext.setProperty(String, Object)
。 然后只需注入ContainerRequestContext
@Override public void filter(ContainerRequestContext crc) throws IOException { MyObject obj = new MyObject(); crc.setProperty("myObject", myObject); } @POST public Response getResponse(@Context ContainerRequestContext crc) { return Response.ok(crc.getProperty("myObject")).build(); }
直接注入MyObject
另一种select是使用Jersey 2提供的HK2function。
创build一个工厂注入ContainerRequestContext
并返回MyObject
。 例如
import javax.inject.Inject; import javax.ws.rs.container.ContainerRequestContext; import jetty.plugin.test.domain.MyObject; import org.glassfish.hk2.api.Factory; public class MyObjectFactory implements Factory<MyObject> { private final ContainerRequestContext context; @Inject public MyObjectFactory(ContainerRequestContext context) { this.context = context; } @Override public MyObject provide() { return (MyObject)context.getProperty("myObject"); } @Override public void dispose(MyObject t) {} }
然后你需要绑定工厂:
public class InjectApplication extends ResourceConfig { public InjectApplication() { ... register(new AbstractBinder(){ @Override protected void configure() { bindFactory(MyObjectFactory.class) .to(MyObject.class) .in(RequestScoped.class); } }); } }
使用与上面的filter示例中相同的属性设置,您可以使用@Context
注入MyObject
@GET public Response getTest(@Context MyObject myObject) { return Response.ok(myObject.getMessage()).build(); }
- 在
Custom Injection
查看更多信息
UPDATE
请看这个问题,这个实现的问题。
也可以看看:
- 如果您使用的是web.xml而不是ResourceConfig
我有一个解决scheme,这不需要一个DI容器,但仍然给大部分好处。
有两个部分。 首先是如何将实例放入@Context注入机制,而不是在ApplicationConfig对象中提供类。
这里有一个技巧:
private static class CustomContextResteasyBootstrap extends org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap{ private final Map<Class<?>, Object> additionalContextObjects = new HashMap<Class<?>, Object>(); public <E> CustomContextResteasyBootstrap addContextObject(Class<? super E> clazz, E obj){ additionalContextObjects.put(clazz, obj); return this; } @Override public void contextInitialized(ServletContextEvent event) { super.contextInitialized(event); deployment.getDispatcher().getDefaultContextObjects().putAll(additionalContextObjects); } }
你可以这样使用它:
webAppContext.addEventListener( new CustomContextResteasyBootstrap() .addContextObject(MyCustom.class, myCustom) .addContextObject(AnotherCustom.class, anotherCustom) // additional objects you wish to inject into the REST context here );
现在你可以用@Context注解来使用这些类:
@GET public MyCustom echoService(@Context MyCustom custom) { return custom; }
难题的下一部分是如何提供每个请求的上下文对象。 为此,请在jax-rs调用层次结构顶部附近添加以下代码(基本上,在该行下面调用的任何东西都可以访问上下文对象):
ResteasyProviderFactory.pushContext(MyContextSpecific.class, new MyContextSpecific());
然后,您可以通过任何低于该级别的注射来引用这个:
@GET public String contextSpecificEchoService(@Context MyContextSpecific contextSpecific) { return custom.toString(); }
这是穷人的DI,但对于embedded式rest服务器来说,它确实很好。