使@ApplicationScoped JSF托管bean可序列化是一种不好的做法?

时间:2012-06-22 08:13:31

标签: jsf jsf-2 scope

我们在基于JSF的Java Web应用程序中不断获得followng异常,并且谷歌搜索它表明它可能是由应用程序范围的jsf托管bean可序列化引起的。

 java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.apache.catalina.session.StandardSessionFacade
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at org.apache.catalina.session.StandardSession.readObject(StandardSession.java:1509)
    at org.apache.catalina.session.StandardSession.readObjectData(StandardSession.java:998)
    at org.apache.catalina.session.StandardManager.doLoad(StandardManager.java:394)
    at org.apache.catalina.session.StandardManager.load(StandardManager.java:321)
    at org.apache.catalina.session.StandardManager.start(StandardManager.java:648)
    at org.apache.catalina.core.ContainerBase.setManager(ContainerBase.java:446)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4631)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:799)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:601)
    at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:675)
    at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:601)
    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:502)
    at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1317)
    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:324)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1065)
    at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
    at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
    at org.apache.catalina.core.StandardService.start(StandardService.java:525)
    at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: java.io.NotSerializableException: org.apache.catalina.session.StandardSessionFacade
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at org.apache.catalina.session.StandardSession.writeObject(StandardSession.java:1585)
    at org.apache.catalina.session.StandardSession.writeObjectData(StandardSession.java:1015)
    at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:528)
    at org.apache.catalina.session.StandardManager.unload(StandardManager.java:469)
    at org.apache.catalina.session.StandardManager.stop(StandardManager.java:678)
    at org.apache.catalina.core.StandardContext.stop(StandardContext.java:4882)
    at org.apache.catalina.core.ContainerBase.removeChild(ContainerBase.java:936)
    at org.apache.catalina.startup.HostConfig.undeployApps(HostConfig.java:1359)
    at org.apache.catalina.startup.HostConfig.stop(HostConfig.java:1330)
    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:326)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142)
    at org.apache.catalina.core.ContainerBase.stop(ContainerBase.java:1098)
    at org.apache.catalina.core.ContainerBase.stop(ContainerBase.java:1110)
    at org.apache.catalina.core.StandardEngine.stop(StandardEngine.java:468)
    at org.apache.catalina.core.StandardService.stop(StandardService.java:604)
    at org.apache.catalina.core.StandardServer.stop(StandardServer.java:788)
    at org.apache.catalina.startup.Catalina.stopServer(Catalina.java:408)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.apache.catalina.startup.Bootstrap.stopServer(Bootstrap.java:338)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:416)

在某些情况下,使用@ManagedProperty批注将有问题的托管bean注入到会话范围的bean中。

这是一种不好的做法,还是我没有得到的其他东西?

3 个答案:

答案 0 :(得分:0)

嗯...根据我的理解,只要应用程序已部署,@ApplicationScoped托管bean就会存在。换句话说,我认为您不需要在需要时存储和恢复bean。应该永远在那里。

不是将@ApplicationScoped bean作为@ManagedProperty bean的@SessionScoped注入,而是为什么不尝试将它注入@RequestScoped bean然后注入{ {1}} bean进入你的@RequestScoped bean。 :)

答案 1 :(得分:0)

那是因为JSF托管bean工具没有与Java序列化集成。如果aBean依赖于anotherBean,则将anotherBean的实例注入aBean。由于序列化对象也会对其字段进行序列化,因此anotherBean也将被序列化,这最多是浪费内存,最糟糕的是很难实现(因为它可能具有不可序列化的依赖性......)。

一个体面的依赖注入容器,如CDI或Spring,可以通过将一个可序列化的代理注册到当前的anotherBean到aBean来解决这个问题。这就是为什么人们应该在不同的DI容器中保留豆子的原因之一。 (在JSF中使用CDI或Spring管理的bean非常容易。)

编辑:我对在Java EE 5中被锁定表示同情。在这种情况下,您可能会:

  1. 不要将对应用程序作用域bean的引用保留为依赖项,而是在需要时按名称查找它。
  2. 注入应用程序范围的bean的可序列化代理(或使应用程序范围的bean本身可序列化)。这将涉及挂钩到序列化机制以按名称序列化bean,并在通过查找反序列化时重构它。
  3. 将您的bean拆分为两个:依赖项的一个对象(请求范围),状态的另一个对象(会话范围)。就我个人而言,我发现这种麻烦并且无法有效地封装支持豆,但这只是一种品味问题。

答案 2 :(得分:0)

org.apache.catalina.session.StandardSessionFacade是Tomcat对HttpSession的实现。因此,此异常表明您在一个视图/会话范围的托管bean中具有以下属性:

private HttpSession session;

这是完全错误的。你永远不应该这样做。相同的故事适用于FacesContextExternalContext及其所有工件。永远不应将它们声明为托管bean的属性,但始终在线程局部范围内声明(即在您需要它们的方法块内)。