我正在尝试在嵌入式Jetty设置中为Jersey设置LoggingFilter
。使用的粘合代码如下:
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上都进行了测试。
relevant answer描述了如何使用
web.xml
实现此目的。 最佳答案
如果不是彻底的错误,我认为这是ServletContainer
的已记录行为的非常细微的差别。关于初始化参数的 ServletContainer
docs读为:
答案隐藏在那里。具体来说,如果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
构造函数。 InternalWebComponent
只是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
实例,所以在第二个ResourceConfig
的分支之一中为您构建了if
。构造完成后,立即在新组件上调用WebComponent.init()
(请引用上面的ServletContainer.init()
调用,它来自于此)。在init()
调用内部,将创建文档所引用的“创建的ResourceConfig”,但是在您的情况下,已经存在一个,如我们到达此处的跟踪所示。也就是说,resourceConfig
不为null,因此下面的重要行不会执行: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的初始化参数复制到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参数。