【问题标题】:Getting java.io.NotSerializableException with a spring service when stopping tomcat停止tomcat时使用spring服务获取java.io.NotSerializableException
【发布时间】:2011-11-22 02:32:32
【问题描述】:

我正在使用带有 JSF 2 的 spring 3 我用 Spring bean 替换了 JSF 管理的 bean,方法是在 bean 上添加:

@Component("mybean")
@Scope("session")

在我的 bean 中,我正在自动装配一个 spring 服务(使用注释 @service 声明)

好吧,该服务一切正常,但是当我尝试停止 tomcat 6 时,我的 spring 服务遇到了这个异常

java.io.NotSerializableException

任何想法为什么我会得到这个异常,以及如何解决它。

更新:

在使我的服务实现可序列化后,有时我会遇到以下异常:

java.lang.IllegalStateException: Cannot deserialize BeanFactory with id org.springframework.web.context.WebApplicationContext:/spring_faces: no factory registered for this id
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$SerializedBeanFactoryReference.readResolve(DefaultListableBeanFactory.java:972)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1061)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1762)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:480)
    at org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor.readObject(AbstractBeanFactoryPointcutAdvisor.java:98)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1849)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1667)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1323)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:480)
    at org.springframework.aop.framework.AdvisedSupport.readObject(AdvisedSupport.java:550)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1849)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
    at org.apache.catalina.session.StandardSession.readObject(StandardSession.java:1496)
    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.start(ContainerBase.java:1057)
    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(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)

请指教。

【问题讨论】:

    标签: spring jakarta-ee spring-mvc dependency-injection inversion-of-control


    【解决方案1】:

    查看错误,看来tomcat正在尝试序列化整个spring上下文,我认为这可能是由于您在Service上实现了Serializable。我在想你可能需要这样做,我不太了解 JSF,但我对作用域 bean 的理解让我想,你可能需要这样的东西

        @Component
        @Scope(proxyMode=ScopedProxyMode.TARGET_CLASS, value="session")
        public class MyBean implements Serializable
        {
           //no need to implement serializable on service
           @Autowired(required=true)
           private MyService service;
        }
    

    【讨论】:

    • 下面的proxyMode=ScopedProxyMode.TARGET_CLASS是什么意思,autowiring需要required=true是什么意思
    • 当我尝试这样做时,我得到了异常:org.springframework.aop.framework.AopConfigException:无法代理目标类,因为 CGLIB2 不可用。将 CGLIB 添加到类路径或指定代理接口。
    • 你不需要required为true(只是指示容器这个依赖不能被忽略)它是默认的,你需要这个依赖cglibcglib artifactId>2.2.2,如果将CGLIB放在classpath中,则可以使用JDK或CGLIB创建代理,spring使用CGLIB创建prxoy。
    • 好的,我会试试的,但你没有告诉我,代码是什么意思:proxyMode=ScopedProxyMode.TARGET_CLASS
    • 阅读本节 3.4.4.5。从下面的文档static.springsource.org/spring/docs/2.5.x/reference/…
    【解决方案2】:

    你得到这个异常是因为这个类没有实现Serializable。 Tomcat 在即将重新启动/重新部署时将当前正在运行的HttpSession 对象(包括其所有属性)序列化到磁盘,以便在循环后恢复它们。会话范围的对象存储为HttpSession 的属性,因此它们也需要实现Serializable 才能在重新启动/重新部署后继续存在。

    如果你想让它们Serializable,那么相应地实现它:

    public class YourSpringService implements Serializable {}
    

    否则,只需忽略异常或在 Tomcat 的配置中关闭序列化会话到磁盘。

    请注意,同样的故事也适用于 JSF 视图/会话范围的 bean。

    【讨论】:

    • 所以问题是我的 spring bean(替代 jsf 托管 bean)是会话范围的并且实现了 Serializable,这个 bean 中使用的任何 spring 服务也必须实现 Serializable ?
    • 如果您需要它们可序列化,那么可以。否则将它们标记为瞬态。我只是不保证Spring复活后会重新注入,这超出了我的认知(我不做Spring)。
    • 我认为问题是服务的@autowired,我认为如果您将服务设为瞬态,那么服务将不会被序列化(因为您无法以任何方式真正序列化它,它只是一个代理)
    • 让服务瞬态是什么意思?
    • @Jsword:使用transient关键字。例如。 private transient Foo foo;。这会跳过序列化的属性。
    【解决方案3】:

    好吧,我终于可以让它正常工作了:

    1- 服务:

    @Service
    @Scope("singleton")
    public class PersonService{
    
    }
    

    2- Spring Managed Bean:

     @Component("person")
       @Scope("session")
       public class PersonBean implements Serializable{
    
       @Inject
       private PersonService personService;
    
       }
    

    等待您的反馈。

    【讨论】:

      【解决方案4】:

      我不得不使用readObject() + static ApplicationContext hack 来解决问题:

      @Component
      @Scope(value = SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
      public class FlashMessages implements Serializable {    
      
          @Autowired
          transient private SomeBean someBean;
      
          private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
              ois.defaultReadObject();
              // restore someBean field on deserialization
              SpringUtils.getContext().getAutowireCapableBeanFactory().autowireBean(this);
          }
      
      }
      
      @Component
      public class SpringUtils implements ApplicationContextAware {
      
          static ApplicationContext applicationContext;
      
          @Override
          public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
              SpringUtils.applicationContext = applicationContext;
          }
      
          public static ApplicationContext getContext() {
              return applicationContext;
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-04
        • 1970-01-01
        • 2019-06-30
        • 2018-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多