5

我正在尝试LoggingFilter在嵌入式 Jetty 设置中为 Jersey 进行配置。使用的胶水代码如下:

ServletContainer servletContainer = new ServletContainer(application);
ServletHolder servletHolder = new ServletHolder(servletContainer);
servletHolder.setInitParameter("com.sun.jersey.config.feature.Debug", "true");
servletHolder.setInitParameter("com.sun.jersey.config.feature.Trace", "true");
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", 
  "com.sun.jersey.api.container.filter.LoggingFilter");
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", 
  "com.sun.jersey.api.container.filter.LoggingFilter");

但是日志过滤器实际上被忽略了,我在控制台中没有看到相关的日志。我怎样才能做到这一点?在 Jersey 1.x 和 2.x 上都进行了测试。

相关答案描述了如何使用web.xml.

4

2 回答 2

4

我认为这是记录行为的一个非常微妙的细微差别,ServletContainer如果它不是一个彻底的错误。关于 init params 主题的ServletContainer文档如下:

所有初始化参数都作为创建的 ResourceConfig 的属性添加。

答案就藏在那里。具体来说,如果 ResourceConfig 实例不是由 ServletContainer 创建的,则 servlet 初始化参数不会作为属性添加,因此不会影响应用程序的配置。当您提供自己的Application实例时,就像您对 . 所做的那样new ServletContainer(application),初始化大致遵循以下过程:

您的代码使用您的实例调用以下ServletContainer构造函数:Application

public ServletContainer(Application app) {
    this.app = app;
}

容器将您初始化ServletContainer为典型Servlet生命周期的一部分:

protected void init(WebConfig webConfig) throws ServletException {
    webComponent = (app == null)
            ? new InternalWebComponent()
            : new InternalWebComponent(app);
    webComponent.init(webConfig);
}

您的Application实例进入InternalWebComponent构造函数。AnInternalWebComponent只是对 的轻微定制WebComponent,因此:

InternalWebComponent(Application app) {
    super(app);
}

调用:

public WebComponent(Application app) {
    if (app == null)
        throw new IllegalArgumentException();

    if (app instanceof ResourceConfig) {
        resourceConfig = (ResourceConfig) app;
    } else {
        resourceConfig = new ApplicationAdapter(app);
    }
}

在这里,由于您Application直接提供了一个实例,因此 aResourceConfig在该 second 的一个分支中为您构建if。构建后立即在WebComponent.init()新组件上调用(请参阅ServletContainer.init()上面的调用,我们来自哪里)。在此调用中,init()创建文档引用的“创建的 ResourceConfig” ,但在您的情况下,已经存在一个,如我们遵循的路径所示。即,不为空,因此下面的重要行不执行:resourceConfig

public void init(WebConfig webConfig) throws ServletException {
    ...
    if (resourceConfig == null)
        resourceConfig = createResourceConfig(config);
    ...
}

createResourceConfig()方法(仍在WebComponent)显示为:

private ResourceConfig createResourceConfig(WebConfig webConfig)
        throws ServletException {
    final Map<String, Object> props = getInitParams(webConfig);
    final ResourceConfig rc = createResourceConfig(webConfig, props);
    rc.setPropertiesAndFeatures(props);
    return rc;
}

您可以在该调用中看到setPropertiesAndFeatures()用于将 servlet 的 init 参数复制到ResourceConfig实例中。不幸的是,这是进行该调用的唯一地方,在您的情况下,执行永远不会在这里进行,主要是因为您使用了非默认ServletContainer构造函数之一。

我希望原始作者ServletContainer只使用一个无参数构造函数编写,而其他两个是后来添加的,以便在 Servlet 3.0 容器中使用,而没有意识到引入了这种行为。否则,我希望在文档中看到一些提及它。

所以,长话短说:要么使用默认ServletContainer构造函数,要么自己找到一种方法来处理这部分:

Map<String, Object> props = getInitParams(webConfig);
rc.setPropertiesAndFeatures(props);

第一种方法可能是最简单的。例如,您也可以将您的Application类指定为 init 参数,只要没有什么需要您提前实例化它,例如:

servletHolder.setInitParameter("javax.ws.rs.Application", "org.foo.MyApplication");

这样,将采用“正常”初始化路径,这意味着WebComponent将为您创建ResourceConfig并正确应用 init 参数。

于 2013-04-14T19:40:52.017 回答
0

我想你可能做错了。

// Creating an instance of Jersey servlet, right?
ServletContainer servletContainer = new ServletContainer(application);

// Putting it in a container by reference.
ServletHolder servletHolder = new ServletHolder(servletContainer);

此页面不会像您那样创建 servlet:

ServletHolder sh = new ServletHolder(WicketServlet.class);

这样 Jetty 创建一个实例,并调用 servlet 的init(). 在您的情况下,您可能需要致电init(),但我不确定您将在哪里获得ServletConfiguration实例。

更新: 你应该这样尝试:

  ServletHolder servletHolder = new ServletHolder(ServletContainer.class);
  servletHolder.setInitParameter("javax.ws.rs.Application", "MyRESTApplication");
  servletHolder.setInitParameter("com.sun.jersey.config.feature.Debug", "true");
  servletHolder.setInitParameter("com.sun.jersey.config.feature.Trace", "true");
  servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters",
      "com.sun.jersey.api.container.filter.LoggingFilter");
  servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters",
      "com.sun.jersey.api.container.filter.LoggingFilter");

  ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
  contextHandler.addServlet(servletHolder, "/services/*");
  server.setHandler(contextHandler);
于 2013-04-14T18:24:34.990 回答