泽西岛:ContainerRequestFilter 没有获得上下文 ServletRequest

Posted

技术标签:

【中文标题】泽西岛:ContainerRequestFilter 没有获得上下文 ServletRequest【英文标题】:Jersey: ContainerRequestFilter does not get Context ServletRequest 【发布时间】:2015-07-10 13:52:12 【问题描述】:

要查看此问题的完整代码,请参阅此 github

https://github.com/mobiusinversion/web-application

我还创建了这个 Jersey Jira

https://java.net/jira/browse/JERSEY-2851

我正在使用 Jersey 2.15 开发 ContainerRequestFilter。这是一个嵌入的 Jetty 应用程序,它被隐藏在一个 jar 中。

在 Jetty 启动器(主类)中:

public static void main(String[] args) throws Exception 
    ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
    context.setContextPath("/");
    Server jettyServer = new Server(10005);
    jettyServer.setHandler(context);
    ServletHolder jerseyServlet = context.addServlet(ServletContainer.class, "/*");
    jerseyServlet.setInitOrder(0);
    jerseyServlet.setInitParameter(ServerProperties.PROVIDER_PACKAGES, ServletConstants.COMPONENT_SCAN_ROOT);

    try 
        System.out.println("Starting Jetty");
        jettyServer.start();
        System.out.println("Jetty Started");
        jettyServer.join();
     catch (Exception e) 
        System.out.println("Could not start server");
        e.printStackTrace();
     finally 
        jettyServer.destroy();
    

我有一个通过提供程序包含的过滤器

@Provider
public class ExampleProvider implements DynamicFeature 

    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext featureContext) 
        ExampleFilter exampleFilter = new ExampleFilter();
        featureContext.register(exampleFilter);
    

然后在过滤器中:

public class ExampleFilter implements ContainerRequestFilter 

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

    @Context
    private HttpServletRequest servletRequest;

    @Override
    public void filter(ContainerRequestContext containerRequestContext) throws IOException 
        logger.info("IP ADDRESS " + servletRequest.getRemoteAddr());
        // ...
    


然而这会产生一个NullPointerException:

Caused by: java.lang.NullPointerException: null
at com.example.filters.ExampleFilter.filter(ExampleFilter.java:29) 
at org.glassfish.jersey.server.ContainerFilteringStage.apply(ContainerFilteringStage.java:131) 
at org.glassfish.jersey.server.ContainerFilteringStage.apply(ContainerFilteringStage.java:67) 

我做错了什么,我该如何解决?

更新:包括为 Jetty 和 Jersey 输入的 pom

    <properties>
        <jersey.version>2.15</jersey.version>
        <jetty.version>9.2.6.v20141205</jetty.version>
    </properties>

    <!-- Jersey -->
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>$jersey.version</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>$jersey.version</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey</groupId>
        <artifactId>jersey-bom</artifactId>
        <version>$jersey.version</version>
        <type>pom</type>
        <scope>compile</scope>
    </dependency>

    <!-- Jetty -->
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>$jetty.version</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlet</artifactId>
        <version>$jetty.version</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlets</artifactId>
        <version>$jetty.version</version>
    </dependency>

【问题讨论】:

我很确定这会起作用,因为在这些情况下不会报告此问题。你看过github吗?它非常准系统。在这种情况下,很明显 Jetty 或 Jersey 或两者的组合都有错误。这个赏金是找到一个不涉及等待任何一组响应的解决方案。当然,一种解决方案是完全放弃 Jetty,但我不希望这样做。 【参考方案1】:

错误在于您在ExampleRequestFilterProvider手动创建ExampleRequestLoggingFilter 的实例。依赖注入仅适用于由容器本身创建和管理的实例,例如ExampleRequestFilterProvider。这就解释了为什么 @Context 注入在您手动创建的实例中似乎不起作用。

解决方案是将注入点移动到ExampleRequestFilterProvider,然后将其传递给ExampleRequestLoggingFilter 的构造函数。

@Provider
public class ExampleRequestFilterProvider implements DynamicFeature 

    @Context
    private HttpServletRequest request;

    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext featureContext) 
        ExampleRequestLoggingFilter exampleRequestLoggingFilter = new ExampleRequestLoggingFilter(request);
        featureContext.register(exampleRequestLoggingFilter);
    


我在这里测试了它(感谢 Git 项目!)它对我有用。

请注意,您在此处传递的不是实际的 HttpServletRequest 实例,而是一个容器管理的代理,它在每个方法调用上进一步委托给实际实例,因此这里无需担心完整性和线程安全。

【讨论】:

Bam,就像那样......谢谢伙计,这真的很有帮助。显然,我需要阅读有关这些东西如何更好地工作的书籍。我只能在 22 小时内奖励赏金,但我会的。非常感谢。 不客气。不急于赏金。您甚至可以将其保持打开状态,直到它过期(并自动获得奖励)。这增加了从浏览赏金问题的人那里获得支持的机会(这样您就可以赢回代表),尤其是在到期前一天。 听起来不错,可以。干杯。 (+1 good catch) 我只是将过滤器注册为一个类而不是一个实例。它的工作原理是一样的,但是将 servlet 请求注入功能对我来说看起来是错误的 :-) @peeskillet:它确实会引起一些瘙痒,因为request 实例实际上是一个代理并不是立即可见的。如果 ExampleRequestLoggingFilter 被创建为匿名类,它会不那么痒。或者也许通过将变量名request 重命名为requestProxy。啊好吧..这取决于大卫:)

以上是关于泽西岛:ContainerRequestFilter 没有获得上下文 ServletRequest的主要内容,如果未能解决你的问题,请参考以下文章

如何从泽西岛资源生成 JSON?

泽西岛:不存在 WebApplication 提供程序

泽西岛的 JSON ArrayList

泽西岛和过滤器异常处理

泽西岛:ContainerRequestFilter 没有获得上下文 ServletRequest

AsyncResponse ConnectionCallback 不会在泽西岛触发