如何将一个对象注入Jersey请求上下文?

31

我有这样一个场景,我想编写一个过滤器,并希望该过滤器将某些对象插入到当前请求中,并将其传递,以便当资源类获取请求时可以使用该对象。

过滤器类

@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 "";
}
2个回答

52
你可以直接使用 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);
            } 
        });
    }
}

使用与上面过滤器示例相同的属性设置,然后您只需使用@Context注入MyObject

@GET
public Response getTest(@Context MyObject myObject) {
    return Response.ok(myObject.getMessage()).build();
}


更新

请参见此问题,了解此实现的问题。

另请参阅:


我有一个很大的请求:您能否尝试以相反的方向回答这个问题(例如,我想在前端级别向RequestContext添加一些对象,并在Spring Boot服务器中接收它)? 这是我的帖子链接:https://stackoverflow.com/questions/46211601/attaching-attribute-to-requestcontext-pass-element-from-frontend-to-backend。 - Haskell Fun
自从Jersey 2.26版本以后,对HK2的强依赖已经消失了,现在必须使用Java的Supplier<T>接口来代替Factory<T> - bramhaag

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();
}

这是一种简易的依赖注入方式,但对于嵌入式REST服务器来说非常有效。

5
好的,我会尽力进行翻译。问题的标题是“Jersey”,而不是“resteasy”。 - Yannick Menager
我有一个很大的请求:你能否尝试以相反的方向回答这个问题(例如,我想在前端级别向RequestContext添加一些对象,并在spring-boot服务器中接收它)。这是我的帖子链接:https://stackoverflow.com/questions/46211601/attaching-attribute-to-requestcontext-pass-element-from-frontend-to-backend - Haskell Fun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接