4

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)
4

1 回答 1

1

到目前为止,这似乎是 Weblogic 12.1.3 中的一个实际错误/限制,因此我将我的解决方法发布为可能的解决方案。

要使Statefulbean 成功通过钝化,需要实现用javax.ejb.PrePassivate和注释的方法javax.ejb.PostActivate。该@PrePassivate方法将使无状态 bean 引用指向null,并且@PostActivate当 bean 再次被激活时,该方法将对该 bean 执行查找。

@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");
}

如果在接下来的几周左右没有任何评论或其他答案,我会将此答案标记为解决方案。

于 2015-08-03T11:51:18.563 回答