有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java自定义提供程序无法插入到筛选器中

我有一个POJO,我想将其注入到资源和过滤器中:

public final class MyObject { }

我为它实现了一个自定义提供程序:

@Provider
public final class MyProvider
extends AbstractHttpContextInjectable<MyObject>
implements InjectableProvider<Context, Type> {

    @Context private HttpServletRequest request;

    @Override
    public Injectable<MyObject> getInjectable(
            ComponentContext componentContext,
            Context annotation,
            Type type
    ) {
        if (type.equals(MyObject.class)) {
            return this;
        }
        return null;
    }

    @Override
    public ComponentScope getScope() {
        return ComponentScope.PerRequest;
    }

    @Override
    public MyObject getValue(HttpContext httpContext) {
        //in reality, use session info from injected request to create MyObject
        return new MyObject();
    }
}

对象已成功注入我的资源:

@Path("/test")
@ResourceFilters(MyFilter.class)
public final class MyResource {

    @Context private HttpServletRequest request;
    @Context private MyObject myObject;

    @GET
    public String execute() {

        System.out.println(request != null);  //true
        System.out.println(myObject != null); //true

        return "data";
    }
}

但Jersey未能将其注入我的过滤器:

public final class MyFilter implements ResourceFilter {

    @Context private HttpServletRequest request;
    @Context private MyObject myObject;

    @Override
    public ContainerRequestFilter getRequestFilter() {
        return new ContainerRequestFilter() {
            @Override
            public ContainerRequest filter(ContainerRequest containerRequest) {

                System.out.println(request != null);  //true
                System.out.println(myObject != null); //false

                return containerRequest;
            }
        };
    }

    @Override
    public ContainerResponseFilter getResponseFilter() {
        return null;
    }
}

我猜区别在于MyFilter中的注入是使用遵从线程本地实例的代理完成的,这是因为@Context注释的字段在外部类中声明,外部类实例化一次,但它们用于根据每个请求注入对象。在调试期间,当我单步通过filter时,我可以看到MyFilter.request指向一个包装com.sun.jersey.server.impl.container.servlet.ThreadLocalInvoker实例的代理

我的自定义提供程序(或实现)缺少什么,需要在我的过滤器中进行自定义注入

请注意,我目前只能使用Jersey 1.1.4.1(抱歉)

编辑:使用Jersey 1.17,我在启动时会出现异常:

SEVERE: Missing dependency for field: private mypackage.MyObject mypackage.MyFilter.myObject


共 (2) 个答案

  1. # 1 楼答案

    我从JSR-311找到了一个使用^{}可注入接口的解决方法。首先,我必须让我的提供者实现^{}

    @Provider
    public final class MyProvider
    extends AbstractHttpContextInjectable<MyObject>
    implements InjectableProvider<Context, Type>, ContextResolver<MyObject> {
    
        ...
    
        @Override
        public MyObject getContext(Class<?> type) {
            //in reality, using the same logic as before
            return new MyObject();
        }
    }
    

    然后我将一个Providers实例注入到我的过滤器中。调用filter时,我使用它查找ContextResolver中的MyObject并动态检索它:

    public final class MyFilter implements ResourceFilter {
    
        @Context private HttpServletRequest request;
        @Context private Providers providers;
    
        @Override
        public ContainerRequestFilter getRequestFilter() {
            return new ContainerRequestFilter() {
                @Override
                public ContainerRequest filter(ContainerRequest containerRequest) {
    
                    final ContextResolver<MyObject> myObjectResolver =
                                providers.getContextResolver(MyObject.class, null);
                    final MyObject myObject =
                                myObjectResolver.getContext(MyObject.class);
    
                    System.out.println(request != null);  //true
                    System.out.println(myObject != null); //true
    
                    return containerRequest;
                }
            };
        }
    
        ...
    }
    

    多亏了this answer向我透露了Providers的消息。这个解决方案是可行的,但它并不漂亮。我仍然希望在任何地方注入MyObject,然后让它工作,就像HttpServletRequest-我想知道我的提供者缺少什么,需要它来实现这一点

  2. # 2 楼答案

    我在尝试实现相同的目标时遇到了这个问题(即,注入由自定义提供程序实现提供的内容),并发现如果您使用过滤器工厂,自定义注入可以很好地工作

    因此,不要将@Context MyClass myObj注释放入过滤器类,而是在负责创建过滤器的过滤器工厂中放置该类型的带注释字段,并将工厂传递“myObj”作为常规参数

    我不确定这对您的情况是否有帮助,而且我还没有调查过将此用于每个请求提供程序(我的是单例范围的)的含义,所以YMMV