【问题标题】:Intermittetly NPE during parseParameters in Tomcat's Request在Tomcat的请求中的parseParameters期间间歇性NPE
【发布时间】:2011-03-06 15:20:51
【问题描述】:

我们在 org.apache.catalina.connector.Request 的 parseParemeters 期间有间歇性 NPE。在线的用户越多,这种 NPE 发生的越多。 JBoss 重新启动后,NPE 会消失一段时间。在 24 小时内,我们会收到 1 到 400 多个 NPE。调用哪个服务并不重要。任何服务请求都可以在这个 NPE 中结束。

java.lang.NullPointerException 在 org.apache.catalina.connector.Request.parseParameters(Request.java:2517) 在 org.apache.catalina.connector.Request.getParameterNames(Request.java:1102) 在 org.apache.catalina.connector.Request.getParameterMap(Request.java:1082) 在 org.apache.catalina.connector.RequestFacade.getParameterMap(RequestFacade.java:414) 在 javax.servlet.ServletRequestWrapper.getParameterMap(ServletRequestWrapper.java:166) 在 org.jboss.seam.mock.MockExternalContext.getRequestParameterValuesMap(MockExternalContext.java:307) 在 org.jboss.seam.faces.Parameters.getRequestParameters(Parameters.java:61) 在 org.jboss.seam.Component.injectParameters(Component.java:1586) 在 org.jboss.seam.Component.inject(Component.java:1556) 在 org.jboss.seam.core.BijectionInterceptor.aroundInvoke(BijectionInterceptor.java:61) 在 org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) 在 org.jboss.seam.transaction.TransactionInterceptor$1.work(TransactionInterceptor.java:97) 在 org.jboss.seam.util.Work.workInTransaction(Work.java:61) 在 org.jboss.seam.transaction.TransactionInterceptor.aroundInvoke(TransactionInterceptor.java:91) 在 org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) 在 org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:44) 在 org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) 在 org.jboss.seam.security.SecurityInterceptor.aroundInvoke(SecurityInterceptor.java:163) 在 org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) 在 ExceptionInterceptor.aroundInvoke(ExceptionInterceptor.java:51) 在 sun.reflect.GeneratedMethodAccessor289.invoke(未知来源) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 在 org.jboss.seam.util.Reflections.invoke(Reflections.java:22) 在 org.jboss.seam.intercept.Interceptor.aroundInvoke(Interceptor.java:187) 在 org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:72) 在 org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107) 在 org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:185) 在 org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:103) 在 TaskService_$$_javassist_seam_7.getNumberOfUpdatedTasks(TaskService_$$_javassist_seam_7.java) 在 sun.reflect.GeneratedMethodAccessor319.invoke(未知来源) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 在 org.jboss.seam.remoting.gwt.GWTToSeamAdapter.callWebRemoteMethod(GWTToSeamAdapter.java:100) 在 org.jboss.seam.remoting.gwt.GWTService.RPC_invokeAndEncodeResponse(GWTService.java:550) 在 org.jboss.seam.remoting.gwt.GWTService.processCall(GWTService.java:206) 在 org.jboss.seam.remoting.gwt.GWTService$1.process(GWTService.java:120) 在 org.jboss.seam.servlet.ContextualHttpServletRequest.run(ContextualHttpServletRequest.java:53) 在 org.jboss.seam.remoting.gwt.GWTService.getResource(GWTService.java:105) 在 org.jboss.seam.servlet.SeamResourceServlet.service(SeamResourceServlet.java:80) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:717) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) 在 org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) 在 org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) 在 org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) 在 org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:73) 在 org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 在 org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 在 org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433) 在 org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92) 在 org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126) 在 org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 在 org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330) 在 org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:436) 在 org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:384) 在 org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447) 在 java.lang.Thread.run(Thread.java:619)

我们使用 JBoss AS 5.1.0.GA、Seam 2.2.0.GA 和 GWT 2.0.3。 JBoss 通过 mod_jk 接收来自 Apache 2 的请求。提供的行号(Request.java:2517)表明请求的方法为空,尽管firebug(客户端)、Apache和mod_jk的日志显示该方法是POST。

目前,我们既不知道 NPE 的根本原因是什么,也不知道如何解决。我们正在推测这个问题是否与:

  • 垃圾收集(JBoss 以 -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 启动)
  • 在 Tomcat 中请求回收
  • Tomcat 中的过滤器链回收
  • mod_jk 平衡

我们可以做些什么来找出这个问题的原因?有没有办法解决这个问题?

非常感谢任何帮助或建议。

谢谢!

--

我们很幸运,能够在 NPE 期间调试堆栈跟踪。我们发现,MockExternalContext 中的请求对象并不总是与SeamResourceServlet 接收的请求对象相匹配。有时MockExternalContext 中的请求对象是新的并且包含org.apache.coyote.Request 的新实例,所有字段都设置为null。如果可以处理请求,则SeamResourceServlet收到的请求对象与MockExternalContext中的相同。

能否请任何 Seam 专家帮助我们,告诉我们在上面的堆栈跟踪中何时何地创建了 org.jboss.seam.faces.Parameters 使用的 MockExternalContext?在什么情况下Seam会用一个新的请求对象而不是SeamResourceServlet提供的对象来初始化MockExternalContext

我已经在Seam forum 中交叉发布了这个问题。

--

更新

与此同时,我们找到了 NPE 的原因:

由于我们在客户端使用 GWT,所有客户端与服务器的通信都是通过 GWT-RPC 异步完成的。在极少数情况下,注销调用会超过另一个仍在处理的 RPC。注销调用使会话无效,因此其他 RPC 无法正常完成,导致 ServletLifecycle.endRequest(request);在 ContextualHttpServletRequest 中。这个异常由 Seam 的 ExceptionFilter 处理。不幸的是,ExceptionFilter也无法正常完成,因为Session无效导致如下错误:

错误 [Seam Resource Servlet].error: Servlet.service() for servlet Seam Resource Servlet 抛出异常 java.lang.IllegalStateException:提交响应后无法创建会话 在 org.apache.catalina.connector.Request.doGetSession(Request.java:2338) 在 org.apache.catalina.connector.Request.getSession(Request.java:2094) 在 org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:833) 在 javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:216) 在 org.jboss.seam.mock.MockExternalContext.getSessionMap(MockExternalContext.java:357) 在 org.jboss.seam.contexts.FacesLifecycle.beginExceptionRecovery(FacesLifecycle.java:86) 在 org.jboss.seam.web.ExceptionFilter.endWebRequestAfterException(ExceptionFilter.java:96) 在 org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:70) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) 在 org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) 在 org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) 在 org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:73) 在 org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 在 org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 在 org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433) 在 org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92) 在 org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126) 在 org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 在 org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330) 在 org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:436) 在 org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:384) 在 org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447) 在 java.lang.Thread.run(Thread.java:619)

在 ExceptionFilter 中创建的 MockExternalContext,“不知何故”停留在应用程序上下文中,“有时”用于处理请求。它甚至可以在重新部署我们的应用程序时幸存下来,因此我们必须重新启动 JBoss 才能摆脱 NPE。

【问题讨论】:

  • 这看起来有点像线程安全漏洞。 JBossAS 5 使用 Tomcat 的分叉版本,因此我建议使用 JBoss 而不是 Apache 提交错误。
  • 谢谢你的建议,斯卡夫曼。我们也考虑到了这一点(在 Tomcat 中请求回收)。在拥有许多 NPE 的同时重新启动 JBoss 会立即有所帮助,这一事实在这个方向上给出了另一个提示。我会提交错误报告。
  • 用我们在调试 NPE 时发现的更多见解编辑问题。
  • 这不是一个安全的错误。正如上面的更新所描述的,问题是注销调用超过了其他异步调用。

标签: tomcat jboss seam


【解决方案1】:

非常非常感谢您的这篇文章。这个错误是我们几周的噩梦。我们的配置是:GWT 2.0.4、Seam 2.2.1 CR2、JBoss AS 5.1.0。我们在我们的应用程序中修补了注销机制,但它仍然返回(虽然很少)。现在看来,当事务在 EJB 层中持续时间过长时会发生这种情况。现在我们准备好摆脱 Seam,它导致的问题超出了我们的处理范围。

更新: 当“ServiceImpl”组件的范围从“SESSION”更改(只是将其删除)为默认值时,这个奇怪的错误完全消失了。还添加了注释 @BypassInterceptors。同时,我为我们的应用程序准备了 Seam-GWT 桥接器的替代品。这是 Guice + gwt-dispatch。非常快速和可靠的解决方案。

【讨论】:

    猜你喜欢
    • 2011-03-13
    • 2015-07-05
    • 1970-01-01
    • 2012-12-14
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-30
    相关资源
    最近更新 更多