我有一个 facelet 在会话超时后 30 秒刷新浏览器窗口,例如
<a4j:region>
<h:form>
<a4j:poll id="poll" interval="#{(session.maxInactiveInterval + 30)*1000}" onbegin="window.document.location.href='/Patrac'"/>
</h:form>
</a4j:region>
重新加载时,facelet 会导致在 SFSB 上调用方法,例如
<ui:define name="title">PATRAC - #{workflowManager.currentWorkflow.screenTitle}</ui:define>
SFSB 是会话范围的。
@SessionScoped
@Stateful
public class WorkflowManager {
...
public Workflow getCurrentWorkflow() { return currentWorkflow; }
@PreDestroy public void bye() { System.out.println("Destroying: "+ getClass().getName() +", ID = "+ getId()); }
}
85% 的时间屏幕刷新无意外:
15:56:44,951 INFO [stdout] (http-/127.0.0.1:8443-1) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -1906221148858801782
15:56:44,968 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/
15:58:01,343 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -3546919396833964128
15:58:15,288 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-3) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
15:58:15,319 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-4) NoCacheFilter.doFilter() URI: /Patrac/
15:58:15,349 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-3) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
15:58:15,389 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-4) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
15:59:45,771 INFO [stdout] (http-/127.0.0.1:8443-1) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -5655846827584878649
15:59:45,777 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
15:59:45,800 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-1) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
15:59:45,890 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:00:01,356 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 4579100734353654546
16:01:01,363 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 4317425328092070112
16:01:16,518 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-3) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:01:16,526 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-8) NoCacheFilter.doFilter() URI: /Patrac/
16:01:16,544 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-3) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:01:16,572 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-3) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:02:46,894 INFO [stdout] (http-/127.0.0.1:8443-1) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 7360031599060690367
16:02:46,900 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:02:46,923 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-6) NoCacheFilter.doFilter() URI: /Patrac/
16:02:46,950 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-1) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:02:46,975 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:03:01,380 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -5741388414554084710
16:04:01,389 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -1149102875316717372
16:04:01,395 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -7198492156368620025
16:04:17,355 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-7) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:04:17,365 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-8) NoCacheFilter.doFilter() URI: /Patrac/
16:04:17,405 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-7) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:04:17,460 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-8) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:05:47,769 INFO [stdout] (http-/127.0.0.1:8443-7) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -8106288024707282506
16:05:47,773 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-7) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:05:47,808 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-6) NoCacheFilter.doFilter() URI: /Patrac/
16:05:47,809 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-7) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:05:47,856 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-7) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:06:01,409 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 6737131848251158629
16:07:01,419 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -3248726216386741006
16:07:01,423 INFO [stdout] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = -7798326820709515585
16:07:18,188 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-8) NoCacheFilter.doFilter() URI: /Patrac/
16:07:18,188 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:07:18,219 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-1) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
16:07:18,250 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-1) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
但是,有时会发生以下情况:
16:08:48,536 INFO [stdout] (http-/127.0.0.1:8443-7) Destroying: com.patrac.controller.statemachine.WorkflowManager, ID = 601708170643229812
16:08:48,537 INFO [com.patrac.filter.NoCacheFilter] (http-/127.0.0.1:8443-7) NoCacheFilter.doFilter() URI: /Patrac/index.xhtml
16:08:48,540 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host]] (http-/127.0.0.1:8443-3) Exception sending request initialized lifecycle event to listener instance of class org.jboss.weld.servlet.WeldListener: javax.ejb.NoSuchEJBException: JBAS016055: EJB has been removed
at org.jboss.as.weld.ejb.StatefulSessionObjectReferenceImpl.getBusinessObject(StatefulSessionObjectReferenceImpl.java:124) [jboss-as-weld-7.2.0.Alpha1-SNAPSHOT.jar:7.2.0.Alpha1-SNAPSHOT]
at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:108) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:105) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at com.patrac.controller.statemachine.WorkflowManager$Proxy$_$$_Weld$Proxy$.toString(WorkflowManager$Proxy$_$$_Weld$Proxy$.java) [Patrac-ejb.jar:]
at java.lang.String.valueOf(String.java:2854) [rt.jar:1.7.0_07]
at java.lang.StringBuilder.append(StringBuilder.java:128) [rt.jar:1.7.0_07]
at org.jboss.weld.context.SerializableContextualInstanceImpl.toString(SerializableContextualInstanceImpl.java:60) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at java.lang.String.valueOf(String.java:2854) [rt.jar:1.7.0_07]
at java.lang.StringBuilder.append(StringBuilder.java:128) [rt.jar:1.7.0_07]
at org.jboss.weld.context.beanstore.AttributeBeanStore.attach(AttributeBeanStore.java:109) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.jboss.weld.context.AbstractBoundContext.activate(AbstractBoundContext.java:66) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.jboss.weld.servlet.WeldListener.requestInitialized(WeldListener.java:141) [weld-core-1.1.9.Final.jar:2012-08-06 19:12]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) [jbossweb-7.0.17.Final.jar:]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.17.Final.jar:]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.17.Final.jar:]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:372) [jbossweb-7.0.17.Final.jar:]
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:897) [jbossweb-7.0.17.Final.jar:]
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:634) [jbossweb-7.0.17.Final.jar:]
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:2039) [jbossweb-7.0.17.Final.jar:]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_07]
16:08:48,561 WARNING [com.patrac.controller.exceptionhandler.ViewExpiredExceptionHandler] (http-/127.0.0.1:8443-7) Attempt to access an expired view: /index.xhtml from remote host: 127.0.0.1
堆栈跟踪始终出现在浏览器窗口中,因此在会话超时时浏览器发出请求后会发生这种情况。只有在 SFSB 被销毁的几乎同时(毫秒内)收到请求时才会发生这种情况。它永远不会在注销时发生,尽管 302 REDIRECT 会导致浏览器在 SFSB 被销毁后仅几毫秒内发出请求。似乎不仅时间是一个因素,而且每次发生这种情况时都会抛出 ViewExpiredException 。
似乎正在发生的事情是因为会话超时但 EJB 没有立即删除,当浏览器发出请求时,JBoss 从超时会话中删除 EJB,然后抛出 EJB 已被删除而不是首先删除的异常创建一个新的 EJB 并将其绑定到新会话。
如何处理 NoSuchEJBException,或者更好地完全避免它?