如何避免Hibernate Interceptor审计中的StackOverflow异常

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (165)

这是我的拦截器课程

public class AuditInterceptor extends EmptyInterceptor {
    private static final long serialVersionUID = 1L;

    private Set<Auditable> inserts = new HashSet<>();
    private Set<Auditable> updates = new HashSet<>();
    private Set<Auditable> deletes = new HashSet<>();

//  @PrePersist
//  public void doPrePersist(final Auditable entity) {
//      if (entity.isAudited()) {
//          logIt("Create", entity);
//      }
//  }
//  
//  @PreUpdate
//  public void doPreUpdate(final Auditable entity) {
//      if (entity.isAudited()) {
//          logIt("Update", entity);
//      }
//  }
//  
//  @PreRemove
//  public void doPreRemove(final Auditable entity) {
//      if (entity.isAudited()) {
//          logIt("Delete", entity);
//      }
//  }
//  
    @Override
    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types)
        throws CallbackException {

        if (entity instanceof Auditable && ((Auditable)entity).isAudited()){
            inserts.add((Auditable)entity);
        }
        return super.onSave(entity, id, state, propertyNames, types);

    }

    @Override
    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types)
        throws CallbackException {

        if (entity instanceof Auditable && ((Auditable)entity).isAudited()){
            updates.add((Auditable)entity);
        }
        return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);

    }

    @Override
    public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {

        if (entity instanceof Auditable && ((Auditable)entity).isAudited()){
            deletes.add((Auditable)entity);
        }
    }

    //called before commit into database
    @Override
    public void preFlush(Iterator iterator) {
    }

    //called after committed into database
    @Override
    public void postFlush(Iterator iterator) {
        try {
            for (Auditable entity : inserts) {
                logIt("Saved", entity);
            }

            for (Auditable entity : updates) {
                logIt("Updated", entity); // This is getting called multiple times
            }

            for (Auditable entity : deletes) {
                logIt("Deleted", entity);
            }

        } finally {
            inserts.clear();
            updates.clear();
            deletes.clear();
        }
    }

    public void logIt(String action, Auditable entity) {
        if (!entity.isAudited()) {
            return;
        }
        // I read somewhere that you can't use the same session to write to the db.
        // So I get my ejb session bean (SessionHelper.getSession()).
        // Then I get the injected entitymanager session (.getSession()).
        // Then I get the SessionFactory and open a new session (.getSessionFactory().openSession()).
        Session tempSession = SessionHelper.getSession().getSession().getSessionFactory().openSession();
        Audit auditRecord = new Audit(); // This is an entity
        auditRecord.setAction(action);
//      auditRecord.setDetail(entity.toString()); 
        auditRecord.setCreatedTimestamp(new Timestamp(System.currentTimeMillis())); 
        auditRecord.setEntityPK(entity.getPrimaryKeyDisplay()); 
        auditRecord.setEntityName(entity.getClass().toString());
        tempSession.save(auditRecord);
        tempSession.flush(); // this is doing the calling the next postFlush
        // Since this is a different session, I don't see why it should cascade into an infinite loop since the Audit entity is not itself Auditable (.isAuditable() == false).
    }

}

All of our EJB entities extend an abstract class Auditable, but they may or may not have their .isAuditable() flag set to true. If it is true, it should be added to the appropriate Set then logged by an Audit entity during the postFlush. But the Audit is on a separate Session, and it is a different entity Audit它有它的isAuditable flag set to false, so I am unsure why it is apparently caught in an infinite loop.

The following is the stack trace as requested

Exception in thread "Thread-42" javax.ejb.EJBTransactionRolledbackException: Transaction rolled back
at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleEndTransactionException(CMTTxInterceptor.java:137)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.endTransaction(CMTTxInterceptor.java:117)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:282)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:330)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:242)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.remote.EJBRemoteTransactionPropagatingInterceptor.processInvocation(EJBRemoteTransactionPropagatingInterceptor.java:79)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:43)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:89)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:59)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:55)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ee.component.TCCLInterceptor.processInvocation(TCCLInterceptor.java:45)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:185)
at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler.invokeMethod(MethodInvocationMessageHandler.java:319)
at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler.access$100(MethodInvocationMessageHandler.java:68)
at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler$1.run(MethodInvocationMessageHandler.java:201)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622)
at java.lang.Thread.run(Thread.java:748)
at org.jboss.threads.JBossThread.run(JBossThread.java:122)
at ...asynchronous invocation...(Unknown Source)
at org.jboss.ejb.client.remoting.InvocationExceptionResponseHandler$MethodInvocationExceptionResultProducer.getResult(InvocationExceptionResponseHandler.java:99)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:270)
at org.jboss.ejb.client.TransactionInterceptor.handleInvocationResult(TransactionInterceptor.java:47)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:272)
at org.jboss.ejb.client.ReceiverInterceptor.handleInvocationResult(ReceiverInterceptor.java:132)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:260)
at org.jboss.ejb.client.EJBClientInvocationContext.awaitResponse(EJBClientInvocationContext.java:399)
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:140)
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:121)
at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:104)
at com.sun.proxy.$Proxy11.updateIssue(Unknown Source)
at com.kable.newsstand.knet.issue.FrmIssue2$SavingThread.doSave(FrmIssue2.java:3810)
at com.kable.newsstand.knet.issue.FrmIssue2$SavingThread.run(FrmIssue2.java:3752)
Caused by: javax.transaction.RollbackException: ARJUNA016053: Could not commit transaction.
at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1223)
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:126)
at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.endTransaction(CMTTxInterceptor.java:91)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:282)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:330)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:242)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.remote.EJBRemoteTransactionPropagatingInterceptor.processInvocation(EJBRemoteTransactionPropagatingInterceptor.java:79)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:43)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:89)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:59)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:55)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ee.component.TCCLInterceptor.processInvocation(TCCLInterceptor.java:45)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:185)
at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler.invokeMethod(MethodInvocationMessageHandler.java:319)
at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler.access$100(MethodInvocationMessageHandler.java:68)
at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler$1.run(MethodInvocationMessageHandler.java:201)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622)
at java.lang.Thread.run(Thread.java:748)
at org.jboss.threads.JBossThread.run(JBossThread.java:122)
Caused by: java.lang.StackOverflowError
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.ClassDefiner.defineClass(ClassDefiner.java:57)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:399)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:396)
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:395)
at sun.reflect.MethodAccessorGenerator.generateSerializationConstructor(MethodAccessorGenerator.java:113)
at sun.reflect.ReflectionFactory.generateConstructor(ReflectionFactory.java:388)
at sun.reflect.ReflectionFactory.newConstructorForSerialization(ReflectionFactory.java:351)
at org.jboss.marshalling.reflect.SerializableClass.lookupNonInitConstructor(SerializableClass.java:556)
at org.jboss.marshalling.reflect.SerializableClass.<init>(SerializableClass.java:156)
at org.jboss.marshalling.reflect.SerializableClassRegistry.lookup(SerializableClassRegistry.java:90)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:165)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:128)
at org.jboss.marshalling.cloner.SerializingCloner.cloneFields(SerializingCloner.java:393)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:301)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:276)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:276)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:276)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:251)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:128)
at org.jboss.marshalling.cloner.SerializingCloner.cloneFields(SerializingCloner.java:393)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:301)
at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:276)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:251)
at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:128)
at org.jboss.as.ejb3.remote.LocalEjbReceiver.clone(LocalEjbReceiver.java:313)
at org.jboss.as.ejb3.remote.LocalEjbReceiver.clone(LocalEjbReceiver.java:304)
at org.jboss.as.ejb3.remote.LocalEjbReceiver.processInvocation(LocalEjbReceiver.java:271)
at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:184)
at org.jboss.ejb.client.EJBObjectInterceptor.handleInvocation(EJBObjectInterceptor.java:58)
at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
at org.jboss.ejb.client.EJBHomeInterceptor.handleInvocation(EJBHomeInterceptor.java:83)
at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
at org.jboss.ejb.client.TransactionInterceptor.handleInvocation(TransactionInterceptor.java:42)
at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:125)
at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:255)
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:200)
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183)
at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146)
at com.sun.proxy.$Proxy317.getSession(Unknown Source)
at com.kable.newsstand.kdsejb.audit.AuditInterceptor.logIt(AuditInterceptor.java:107)
at com.kable.newsstand.kdsejb.audit.AuditInterceptor.postFlush(AuditInterceptor.java:89)
at org.hibernate.event.internal.AbstractFlushingEventListener.postPostFlush(AbstractFlushingEventListener.java:401)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:66)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1195)

This last part just keeps repeating

at com.kable.newsstand.kdsejb.audit.AuditInterceptor.logIt(AuditInterceptor.java:115)
at com.kable.newsstand.kdsejb.audit.AuditInterceptor.postFlush(AuditInterceptor.java:89)
at org.hibernate.event.internal.AbstractFlushingEventListener.postPostFlush(AbstractFlushingEventListener.java:401)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:66)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1195)
提问于
用户回答回答于

所以我提出的解决方案是在logIt()之前从集合中删除实体。

public void postFlush(Iterator iterator) {
    try {
        for (Iterator<Auditable> iter = inserts.iterator(); iter.hasNext();) {
//          for (Auditable entity : inserts) {
            Auditable entity = iter.next();
            iter.remove();
            logIt("Saved", entity);
        }

        for (Iterator<Auditable> iter = updates.iterator(); iter.hasNext();) {
//          for (Auditable entity : updates) {
            Auditable entity = iter.next();
            iter.remove();
            logIt("Updated", entity);
        }

        for (Iterator<Auditable> iter = deletes.iterator(); iter.hasNext();) {
//          for (Auditable entity : deletes) {
            Auditable entity = iter.next();
            iter.remove();
            logIt("Deleted", entity);
        }

    } finally {
        inserts.clear();
        updates.clear();
        deletes.clear();
    }
}
用户回答回答于

你的一些假设是错误的,你需要按顺序检查它们。

首先,您需要检查您是否真的获得了会话。如果你得到相同的会话,你就会遇到麻烦,因为onFlush来自调用的logIt将会开始迭代同一个要审计的实体集合。

另一个可能的原因是Audit.isAudited返回true。你也需要检查一下。

所属标签

可能回答问题的人

  • 人生的旅途

    10 粉丝484 提问5 回答
  • 无聊至极

    4 粉丝504 提问5 回答
  • 骑牛看晨曦

    5 粉丝522 提问4 回答
  • 嗨喽你好

    7 粉丝480 提问4 回答

扫码关注云+社区

领取腾讯云代金券