【问题标题】:How to inject an object into jersey request context?如何将对象注入球衣请求上下文?
【发布时间】:2015-02-24 06:35:02
【问题描述】:

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

过滤器类

@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 "";
}

【问题讨论】:

    标签: java dependency-injection jersey jersey-2.0


    【解决方案1】:

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


    更新

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

    另请参阅:

    【讨论】:

    • 我有一个巨大的要求:你能尝试反向回答这个问题吗(例如,我想在前端级别向RequestContext 添加一些对象,并在spring-boot 服务器中接收它) .这是我的主题:stackoverflow.com/questions/46211601/…
    【解决方案2】:

    我有一个不需要 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,但它确实适用于嵌入式休息服务器。

    【讨论】:

    • 问题的标题是“球衣”而不是轻松
    • 我有一个巨大的要求:你能尝试反向回答这个问题吗(例如,我想在前端级别向RequestContext 添加一些对象,并在spring-boot 服务器中接收它) .这是我的主题:stackoverflow.com/questions/46211601/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-24
    • 1970-01-01
    • 2015-04-10
    • 2013-09-23
    • 2016-06-27
    • 2011-07-12
    相关资源
    最近更新 更多