我有这个场景,我想编写一个过滤器,我希望这个过滤器将一些对象插入当前请求并传递给它,这样当资源类获取请求时它就可以使用该对象。
过滤类
@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 "";
}
答案 0 :(得分:38)
您可以使用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
的另一个选择是使用Jersey 2提供的HK2功能。
创建工厂,注入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);
}
});
}
}
使用与上面的过滤器示例相同的属性设置,然后只需将MyObject
注入@Context
@GET
public Response getTest(@Context MyObject myObject) {
return Response.ok(myObject.getMessage()).build();
}
Custom Injection
有关此实施的问题,请参阅this question。
另见:
答案 1 :(得分:1)
我已经找到了一个解决方案,它不需要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,但它对嵌入式休息服务器非常有效。