环境:JBoss AS 7.2上的JSF 2.0, Seam 2.3, RF 4.3和PF 5
在两个JSF页面上有一个奇怪的错误。我得到一个LIE(延迟初始化异常)在渲染阶段。
Error Rendering View[/secure/MyPage.xhtml]: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
at com.mycompany.entity.Currency_$$_javassist_17.equals(Currency_$$_javassist_17.java) [:]
at com.sun.faces.renderkit.html_basic.MenuRenderer.isSelected(MenuRenderer.java:724) [jsf-impl-2.1.29.jar:2.1.29]
at com.sun.faces.renderkit.html_basic.MenuRenderer.renderOption(MenuRenderer.java:550) [jsf-impl-2.1.29.jar:2.1.29]
at com.sun.faces.renderkit.html_basic.MenuRenderer.renderOptions(MenuRenderer.java:791) [jsf-impl-2.1.29.jar:2.1.29]
at com.sun.faces.renderkit.html_basic.MenuRenderer.renderSelect(MenuRenderer.java:843) [jsf-impl-2.1.29.jar:2.1.29]
at com.sun.faces.renderkit.html_basic.MenuRenderer.encodeEnd(MenuRenderer.java:297) [jsf-impl-2.1.29.jar:2.1.29]
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:877) [jsf-api-2.1.29.jar:2.1]
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:312) [jsf-impl-2.1.29.jar:2.1.29]
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:309) [jsf-impl-2.1.29.jar:2.1.29]
at com.sun.faces.renderkit.html_basic.GridRenderer.renderRow(GridRenderer.java:185) [jsf-impl-2.1.29.jar:2.1.29]
at com.sun.faces.renderkit.html_basic.GridRenderer.encodeChildren(GridRenderer.java:129) [jsf-impl-2.1.29.jar:2.1.29]
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:847) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1819) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
at javax.faces.render.Renderer.encodeChildren(Renderer.java:168) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:847) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1819) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:447) [jsf-impl-2.1.29.jar:2.1.29]
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:125) [jsf-impl-2.1.29.jar:2.1.29]
at org.jboss.seam.jsf.SeamViewHandler.renderView(SeamViewHandler.java:188) [jboss-seam.jar:2.3.1.Final]
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:286) [jsf-api-2.1.29.jar:2.1]
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120) [jsf-impl-2.1.29.jar:2.1.29]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.29.jar:2.1.29]
有问题的页面开始了一个新的对话,不应该有任何陈腐的东西。大多数时候,这些页面工作正常,但偶尔他们开始抛出这个异常,他们继续抛出这个异常,直到你注销和再次登录。
所以我只能假设某些东西引用了Session作用域bean中的实体。
但问题是它们在哪里被引用,引用了什么?
是否有办法找出哪个组件(ID或哪个行/文件)导致了异常?否则,就是在大海捞针。可能有一个特定的记录器类别,我需要启用(设置为DEBUG或TRACE)?
我已经尝试排除较大的部分的页面,以缩小问题,但随后的页面突然再次工作,即使我添加以前删除的部分回来了。所以一个合适的Heisenbug;-(
仅根据堆栈跟踪就可以解释很多内容(如果不能理解类和方法名,必要时还可以阅读相关的源代码)。
根据堆栈跟踪,它发生在MenuRenderer
忙于渲染<option>
元素并通过equals()
方法确定项目值是否应该设置selected
属性进行预选时。这个渲染器只被<h:select(One|Many)(Menu|Listbox)>
组件使用。正是在这个组件中,com.mycompany.entity.Currency
实例代表<f:selectItems>
或<h:selectMany(Menu|Listbox)>
的单个项目值,就像value="#{someBean.someEntity.currencies}"
一样。
显然,Collection<Currency>
是用FetchType.LAZY
而不是FetchType.EAGER
来获取的。因此,Hibernate需要加载它,但是不能这样做,因为在JSF呈现响应阶段,DB会话无处可用。它只能在事务感知的服务方法(如EJB方法)中使用。换句话说,您的数据预加载逻辑是错误的,应该更改为使用FetchType.EAGER
而不是在JSF可以用该数据呈现菜单之前获得Collection<Currency>
。
参见:
- @ manymany (fetch=LAZY)上的selectManyCheckbox中的LazyInitializationException
该错误清楚地说明了在jsf页面(即xhtml)中呈现Menu组件时发生的异常。
at com.sun.faces.renderkit.html_basic.MenuRenderer.isSelected(MenuRenderer.java:724)