Java 如何将对象注入 jersey 请求上下文?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27665744/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 04:49:26  来源:igfitidea点击:

How to inject an object into jersey request context?

javadependency-injectionjerseyjersey-2.0

提问by armin

I have this scenario where I want to write a filter and I want this filter to insert some object into the current request and pass it on so that when the resource class gets the request it can use the object.

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

Filter class

过滤器类

@Override
public void filter(ContainerRequestContext request) throws IOException {
    MyObject obj = new MyObject();
    // Inject MyObject to request which I dont know how
}

Resource Class

资源类

@PUT @Consumes("application/json")
@Path("/")
public String create(
        JSONParam sample,
        @Context MyObject obj) {

    System.out.println(obj.getName());

    return "";
}

采纳答案by Paul Samsotha

You could just use ContainterRequestContext.setProperty(String, Object). Then just inject the ContainerRequestContext

你可以只使用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();
}

Another option to inject the MyObjectdirectly is to use the HK2 functionality Jersey 2 offers.

MyObject直接注入的另一种选择是使用 Jersey 2 提供的 HK2 功能。

Create a factory the inject the ContainerRequestContextand return the MyObject. For example

创建一个工厂,注入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) {}  
}

You then need to bind the factory:

然后你需要绑定工厂:

public class InjectApplication extends ResourceConfig {

    public InjectApplication() {
        ...
        register(new AbstractBinder(){
            @Override
            protected void configure() {
                bindFactory(MyObjectFactory.class)
                        .to(MyObject.class)
                        .in(RequestScoped.class);
            } 
        });
    }
}

With the same setting of the property as in the filter example above, you can then just inject the MyObjectwith the @Context

随着财产如上面的例子过滤器相同的设置,则可以只注射MyObject@Context

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




UPDATE

更新

Please see this questionfor a problem with this implementation.

请参阅此问题以了解实现的问题。

See Also:

也可以看看:

回答by Kevin Day

I've got a solution to this that doesn't require a DI container, but still gives most of the benefit.

我有一个解决方案,不需要 DI 容器,但仍然提供大部分好处。

There's two parts. The first is how to get instances into the @Context injection mechanism instead of providing classes in the ApplicationConfig object.

有两部分。第一个是如何将实例引入@Context 注入机制,而不是在 ApplicationConfig 对象中提供类。

Here's a technique for doing that:

这是一种实现此目的的技术:

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

}

and you use it like this:

你像这样使用它:

        webAppContext.addEventListener(
                new CustomContextResteasyBootstrap()
                    .addContextObject(MyCustom.class, myCustom)
                    .addContextObject(AnotherCustom.class, anotherCustom)
                    // additional objects you wish to inject into the REST context here
            );

now you can use those classes with the @Context annotation:

现在您可以将这些类与 @Context 注释一起使用:

@GET
public MyCustom echoService(@Context MyCustom custom) {
    return custom;
}

The next part of the puzzle is how to provide per-request context objects. To do this, add the following code somewhere near the top of the jax-rs call hierarchy (basically, anything that gets called below this line will get access to the context object):

难题的下一部分是如何提供每个请求的上下文对象。为此,请在 jax-rs 调用层次结构顶部附近的某处添加以下代码(基本上,在此行下方调用的任何内容都可以访问上下文对象):

    ResteasyProviderFactory.pushContext(MyContextSpecific.class, new MyContextSpecific());

You can then reference this via injection anywhere below that level:

然后,您可以通过注入在该级别以下的任何地方引用它:

@GET
public String contextSpecificEchoService(@Context MyContextSpecific contextSpecific) {
    return custom.toString();
}

This is poor-man's DI, but it works really well for embedded rest servers.

这是穷人的 DI,但它非常适合嵌入式休息服务器。