简体   繁体   中英

Stateful bean passivation fails because of Stateless beans references

I am using Weblogic 12c (12.1.3 to be specific) to deploy my (EJB 3.1) application.

In my application, I have a @Stateful bean, which holds references to an EntityManager and other @Stateless beans, injected using @PersistenceContext and @EJB annotations respectively.

My issue is that when my stateful bean is being passivated and serialized to disk, Weblogic tries to serialize the references to the stateless beans as well, and throws a NotSerializableException referring to the bean's proxy that was injected by Weblogic. For comparison - the EntityManager reference is passivated and reactivated without issue at all. It is only the stateless beans who cause issues.

I know I can define @PrePassivate and @PostActivate methods to make my code work, but is there any way I can make the container handle the Stateless beans references on its own?

Attaching sample code which reproduces the problem for me.

Remote bean interface:

import javax.ejb.Remote;

@Remote
public interface Passivate {

    public void doSomething();

}

Stateful Bean implementation:

import javax.ejb.EJB;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Stateful;

@Stateful(mappedName = "PassivateBean")
public class PassivateBean implements Passivate {

    @EJB(mappedName = "NoStateBean")
    private NoState noStateBean;

    @Override
    public void doSomething() {
        System.out.println("Hello world");
    }

    @PrePassivate
    public void prePassivate() {
        // as a workaround - can set noStateBean to null here
    }

    @PostActivate
    public void postActivate() {
        // as a workaround - can lookup and set noStateBean here manually
    }
}

NoState Local interface:

import javax.ejb.Local;

@Local
public interface NoState {

    public void foo();

}

NoState bean implementation:

import javax.ejb.Stateless;

@Stateless(mappedName = "NoStateBean")
public class NoStateBean implements NoState {

    @Override
    public void foo() {
        System.out.println("foo");
    }

}

And finally, the exception I am getting when PassivateBean is being passivated to disk:

<Jul 14, 2015 2:36:20 PM IDT> <Error> <EJB> <BEA-010024> <Error occurred during passivation: java.io.NotSerializableException: passivateTest.NoStateBean_i02rk_Impl
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at weblogic.ejb.container.utils.Serializer.writeObject(Serializer.java:52)
    at passivateTest.PassivateBean_dmn8u8_Impl.writeObject(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at weblogic.ejb.container.swap.PassivationUtils.write(PassivationUtils.java:84)
    at weblogic.ejb.container.swap.DiskSwap.write(DiskSwap.java:173)
    at weblogic.ejb.container.manager.StatefulSessionManager.swapOut(StatefulSessionManager.java:1246)
    at weblogic.ejb.container.cache.LRUCache.passivateNode(LRUCache.java:199)
    at weblogic.ejb.container.cache.LRUCache.timerExpired(LRUCache.java:187)
    at weblogic.timers.internal.TimerImpl.run(TimerImpl.java:304)
    at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:548)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)

As of now, this seems like an actual bug/limitation in Weblogic 12.1.3 so I am posting my workaround as a possible solution.

To make the Stateful bean go through passivation successfully, one needs to implement methods annotated with javax.ejb.PrePassivate and javax.ejb.PostActivate . The @PrePassivate method will make the stateless bean reference point to null , and the @PostActivate method will perform a lookup for that bean when the bean is being activated again.

@PrePassivate
public void prePassivate() {
    noStateBean = null;
}

@PostActivate
public void postActivate() {
    // The lookup string is correct assuming the ejb module is deployed within an ear. If your setup is different the JNDI lookup name may be slightly different.
    noStateBean = InitialContext.doLookup("java:module/NoStateBean!NoState");
}

If there are no comments or other answers in the next couple of weeks or so, I will mark this answer as the solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM