Dropwizard +球衣:"不要求范围及QUOT内;创建自定义批注时 [英] Dropwizard + Jersey : "Not inside a request scope" when creating custom annotation

查看:384
本文介绍了Dropwizard +球衣:"不要求范围及QUOT内;创建自定义批注时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在新泽西州2.17翻出一个简单的Dropwizard 0.8.1 REST服务。上游REST /码头业务我有,增加了一些不错的授权信息获取传递到我的Dropwizard应用程序中的HTTP标头的一些认证服务。

I have a simple Dropwizard 0.8.1 REST service that pulls in Jersey 2.17. Upstream of the REST/Jetty service I have some authentication service that adds some nice authorization information to the HTTP Header that gets passed to my Dropwizard app.

我会的的是能够创造出在我的资源自定义的注释,隐藏所有的杂乱头的解析对POJO垃圾。事情是这样的:

I would love to be able to create a custom annotation in my Resource that hides all the messy header-parsing-to-POJO garbage. Something like this:

 @Path("/v1/task")
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
 public class TaskResource {

      @UserContext                               // <-- custom/magic annotation
      private UserContextData userContextData;   // <-- holds all authorization info

      @GET
      public Collection<Task> fetch() {
           // use the userContextData to differentiate what data to return
      }

我花了最后一天,环视计算器,发现其他几个人谁有同样的问题和出现的(?),以获得某种满足,但我似乎无法避免受到不是一个请求范围内堆栈跟踪,当我尝试这样做。

I've spent the last day looking around stackoverflow and found several other people who had the same issue and appeared (?) to get some satisfaction, but I can't seem to avoid getting a "Not inside a request scope" stack trace when I try to do this.

所以我藏我所有的变化,并试图通过实施直接新泽西文档中的章节22.1和22.2提供的示例:的 https://jersey.java.net/documentation/2.17/ioc.html

So I stashed all my changes and tried to implement the example provided in sections 22.1 and 22.2 by the Jersey documentation directly: https://jersey.java.net/documentation/2.17/ioc.html

与他们一起例如下面(但在我Dropwizard应用程序),我想在我的资源得到一个@SessionInject注释,但它也有不内请求范围炸毁栈每次跟踪。我在做什么错在这里?

Following along with their example (but in my Dropwizard app), I'm trying to get a "@SessionInject" annotation in my Resource, but it also blows up with "Not inside a request scope" stack trace each time. What am I doing wrong here?

资源:

  @Path("/v1/task")
  @Produces(MediaType.APPLICATION_JSON)
  @Consumes(MediaType.APPLICATION_JSON)
  public class TaskResource {

       private final TaskDAO taskDAO;

       @Context
       private HttpServletRequest httpRequest;

       @SessionInject
       private HttpSession httpSession;

       public TaskResource(TaskDAO taskDAO) {
           this.taskDAO = taskDAO;
       }

       @GET
       public Collection<Task> fetch(@SessionInject HttpSession httpSession) {              
           if (httpSession != null) {
                logger.info("TOM TOM TOM httpSession isn't null: {}", httpSession);
           }
           else {
                logger.error("TOM TOM TOM httpSession is null");
           }
           return taskDAO.findAllTasks();
       }

该SessionInjectResolver:

The SessionInjectResolver:

package com.foo.admiral.integration.jersey;

import com.foo.admiral.integration.core.SessionInject;
import javax.inject.Inject;
import javax.inject.Named;

import javax.servlet.http.HttpSession;
import org.glassfish.hk2.api.Injectee;

import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SessionInjectResolver implements InjectionResolver<SessionInject> {

    private static final Logger logger = LoggerFactory.getLogger(HttpSessionFactory.class);

    @Inject
    @Named(InjectionResolver.SYSTEM_RESOLVER_NAME)
    InjectionResolver<Inject> systemInjectionResolver;

    @Override
    public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
        if (HttpSession.class == injectee.getRequiredType()) {
            return systemInjectionResolver.resolve(injectee, handle);
        }

        return null;
    }

    @Override
    public boolean isConstructorParameterIndicator() {
        return false;
    }

    @Override
    public boolean isMethodParameterIndicator() {
        return false;
    }
}

该HttpSessionFactory:

The HttpSessionFactory:

package com.foo.admiral.integration.jersey;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.glassfish.hk2.api.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class HttpSessionFactory implements Factory<HttpSession> {

    private static final Logger logger = LoggerFactory.getLogger(HttpSessionFactory.class);
    private final HttpServletRequest request;

    @Inject
    public HttpSessionFactory(HttpServletRequest request) {
        logger.info("Creating new HttpSessionFactory with request");
        this.request = request;
    }

    @Override
    public HttpSession provide() {
        logger.info("Providing a new session if one does not exist");
        return request.getSession(true);
    }

    @Override
    public void dispose(HttpSession t) {
    }
}

注释:

package com.foo.admiral.integration.core;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface SessionInject {
}

最后,在Dropwizard应用程序类的绑定:

And, finally, the binding in the Dropwizard Application class:

@Override
public void run(TodoConfiguration configuration, Environment environment) throws Exception {
    ...

    environment.jersey().register(new AbstractBinder() {
        @Override
        protected void configure() {
            bindFactory(HttpSessionFactory.class).to(HttpSession.class);

            bind(SessionInjectResolver.class)
                    .to(new TypeLiteral<InjectionResolver<SessionInject>>() { })
                    .in(Singleton.class);
        }
    });

叶老堆栈跟踪:

Caused by: java.lang.IllegalStateException: Not inside a request scope.
at jersey.repackaged.com.google.common.base.Preconditions.checkState(Preconditions.java:149)
at org.glassfish.jersey.process.internal.RequestScope.current(RequestScope.java:233)
at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:158)
at org.jvnet.hk2.internal.MethodInterceptorImpl.invoke(MethodInterceptorImpl.java:74)
at org.jvnet.hk2.internal.MethodInterceptorInvocationHandler.invoke(MethodInterceptorInvocationHandler.java:62)
at com.sun.proxy.$Proxy72.getSession(Unknown Source)
at com.foo.admiral.integration.jersey.HttpSessionFactory.provide(HttpSessionFactory.java:29)
at com.foo.admiral.integration.jersey.HttpSessionFactory.provide(HttpSessionFactory.java:14)

有些线索可能是有用的:

Some clues that may be useful:

1)我注意到的是,在我的HttpSessionFactory永远不会被解雇,所以我不认为工厂是正确识别到DropWizard,日志报表

1) I'm noticing is that the logging statements in my HttpSessionFactory are never getting fired, so I don't think the Factory is correctly identified to DropWizard.

2)如果我改变注释是一个参数,而不是场和移动使用注释成这样的fetch()方法的签名,它不会抛出的堆栈跟踪(但HttpSession中仍然是空,presumably因为工厂在不触发...)

2) If I change the annotation to be a Parameter instead of a Field and move the use of the annotation into the fetch( ) method signature like this, it doesn't throw the stack trace (but the httpSession is still null, presumably because the Factory isn't firing...)

 public Collection<Task> fetch(@SessionInject HttpSession httpSession) {

3)它似乎并不重要,如果我注册environment.jersey()的粘合剂。注册()或environment.jersey()。getResourceConfig()。注册()......他们似乎做同样的事情。

3) It doesn't appear to matter if I "register" the binder with environment.jersey().register() or environment.jersey().getResourceConfig().register()... they appear to do the same thing.

你看到任何明显的问题?在此先感谢!

Do you see any obvious problems? Thanks in advance!

推荐答案

这是怪异的行为。但是,看起来像正在发生的是以下

This is weird behavior. But what looks like is going on is the following


  1. 您已经注册 TaskResource 作为一个实例,而不是作为一个的.class 。这我是pretty肯定的(虽然你没有提到)。

  1. You have registered TaskResource as an instance and not as a .class. This I'm pretty sure of (though you have not mentioned).

register(new TaskResource()); 
/* instead of */ 
register(TaskResource.class);

在做前者,它在一个单独的范围设置的资源。在请求范围后者(除非注明,否则 - 见下文)

Doing the former, it set the resource in a singleton scope. The latter in a request scope (unless annotated otherwise - see below)

在资源模型加载它看到 TaskResource 是一个单,并在的HttpServletRequest 在一个请求范围。如果不是这样,该工厂在每个请求的范围。我猜这两个中的一个。

When the resource model is loading it sees the TaskResource is a singleton, and that the HttpServletRequest is in a request scope. Either that or that the factory is in a per request scope. I'm guessing one of the two.

我认为这实际上可能的的一个范围内的问题,因为在错误消息中提到,但是我pretty肯定的是,在运行时,它会得到一个处理线程本地代理,因为较小的范围。

I thought that it might actually be a scope issue, as mentioned in the error message, but what I'm pretty sure of is that at runtime, it will get handled with a thread local proxy, because of the lesser scope.

您可以看到它与<$固定通过注册 TaskResource 为一类,然后标注的 TaskResource C $ C> @Singleton 。这就是,如果你真的的希望资源类是一个单例。如果没有,那么见好就收落 @Singleton

You can see it fixed by registering the TaskResource as a class, and then annotating the TaskResource with @Singleton. This is if you actually do want the resource class to be a singleton. If not, then just leave off the @Singleton.

奇怪的事情对我来说是它的事实,它启动失败,当资源被显式实例在启动,但工作时,在第一次请求的框架加载(这是发生了什么,当你把它注册为一个类) 。它们都还处在一个单独的范围。

The odd thing to me is that it the fact that it fails on startup when the resource is explicitly instantiated on startup, but works when the framework loads on the first request (which is what happens when you register it as a class). They are both still in a singleton scope.

你可能要考虑的一件事是你是否真的希望资源是单身或没有。你必须担心与单身线程安全的问题,还有一些其他的限制。就个人而言,我preFER,让他们在一个请求范围。你将不得不做一些性能测试,看看是否有很多对应用程序产生影响。

One thing you might want to take into consideration is whether you actually want the resource to be a singleton or not. You do have to worry about thread safety issues with singletons, and there are are some other limitations. Personally, I prefer to keep them in a request scope. You would have to do some performance testing to see if there is much of an impact for your application.

有关参数注入你可能想看看这个帖子

For parameter injection you may want to take a look at this post

另请参见

  • jersey 2 context injection based upon HttpRequest without singleton. My answer should shed some more light.

这篇关于Dropwizard +球衣:&QUOT;不要求范围及QUOT内;创建自定义批注时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆