Jakarta ee 如果被拦截的方法在context.procedure()之后出现回滚异常,如何在EJB拦截器中进行检查?

Jakarta ee 如果被拦截的方法在context.procedure()之后出现回滚异常,如何在EJB拦截器中进行检查?,jakarta-ee,transactions,ejb,interceptor,weblogic12c,Jakarta Ee,Transactions,Ejb,Interceptor,Weblogic12c,我目前正在开发一个企业解决方案,该解决方案作为weblogic12c中的EAR模块部署。我需要编写一个业务逻辑,其中将有实体管理器方法,使用EntityManager接口对数据库执行一些更新,我需要在这些方法周围有一个拦截器,该拦截器将拦截方法调用,并在目标方法未失败时将一些数据推送到JMS队列 由于拦截器与被截获的方法生活在同一事务和安全上下文中,因此如果一个方法失败,它会导致另一个失败,也就是说,如果通过抛出EJBException来完成。我的问题是关于那些在事务实际提交之前无法捕获的事务回

我目前正在开发一个企业解决方案,该解决方案作为weblogic12c中的EAR模块部署。我需要编写一个业务逻辑,其中将有实体管理器方法,使用EntityManager接口对数据库执行一些更新,我需要在这些方法周围有一个拦截器,该拦截器将拦截方法调用,并在目标方法未失败时将一些数据推送到JMS队列

由于拦截器与被截获的方法生活在同一事务和安全上下文中,因此如果一个方法失败,它会导致另一个失败,也就是说,如果通过抛出EJBException来完成。我的问题是关于那些在事务实际提交之前无法捕获的事务回滚异常。因此,即使被拦截的方法获得了一个回滚异常,拦截器也不会立即终止,因为它在同一事务模型中运行,因此它无法捕获这些回滚异常。最终它也被回滚,但同时,数据被推送到JMS队列,这并不是真正需要的

我也不能将JMS队列部分从拦截器中取出,因为作为软件需求,如果模块无法将数据推送到JMS,事务也应该失败并回滚。因此,我在这里试图实现的是,如果被截取的方法失败,事务也会失败,并且除了context.procedure()方法调用之外,拦截器中不应该有任何执行

现在,假设我有一个商业方法:

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Interceptors(TestInterceptor.class)
@Override
public TestBean update(TestBean testBean) {
    try {
        TestEntity testEntity = em.createNamedQuery("TestEntity.findById", TestEntity.class)
                .setParameter("id", testBean.getId())
                .getSingleResult();
        // only some bean conversions before merging
        testEntity.setName(testBean.getName());
        testEntity.setPhone(testBean.getPhone());
        testEntity.setImage(testBean.getImage());
        em.merge(testEntity);
        em.flush();
        testBean.setVersion(testEntity.getVersion());
        logger.debug("Update successful");
        return testBean;
    } catch (Exception ex) {
        logger.debug("update::exception: ", ex);
        throw ex;
    }
}
以及一种web服务方法:

@MethodPrivilege(MethodRole.GENERIC)
@WebMethod
@Override
public String testDataCRUD(@WebParam(name = "auth") AuthRequest authRequest,
                           @WebParam(name = "id") Long id,
                           @WebParam(name = "name") String name,
                           @WebParam(name = "phone") String phone,
                           @WebParam(name = "image") byte[] image,
                           @WebParam(name = "action") Action action) {
    ...
    // build testBean from received parameters
    ...
    try {
        testManager.update(testBean);
        return "SUCCESS";
    } catch(Exception ex) {
        return "FAILED -- UPDATE Error: " + ex.getMessage();
    }
}
最后是拦截器方法:

@AroundInvoke
private Object around(InvocationContext ctx) throws Exception {
    Object testParam = null;
    TestBean testBean = null;

    logger.debug("Test intercepted");

    try {
        testParam = ctx.proceed();
    } catch(Exception ex) {
        logger.debug("Interceptor exception ", ex);
        throw new EJBException("Target method raised an exception");
    }
    // do some bean conversion here
    ...
    ...
    // construct the message object here
    boolean success = jmsNotifier.send(message, false);
    if(!success) {
        throw new Exception("JMS failed.");
    }

    logger.debug("Successfully sent to jms");

    return testParam;
}
现在,如果业务方法获得回滚异常,服务层可以捕获它,因为业务方法启动了一个新事务。但到目前为止,我无法在ctx周围的try-catch块中捕获它;结果,代码继续并将数据推送到jms队列,然后在事务完成时获取异常。我如何解决这个问题? 注:很抱歉我的英语不好,如果我需要进一步澄清,请告诉我

更新:(在的评论之后)

为了描述我这样做的原因——例如,我向现有ejb项目添加了一个额外的jar包,服务层和业务/实体管理器层来自现有的应用程序。现在,我添加的额外ejbjar围绕目标业务方法执行一些额外的工作,可以有很多这样的方法。因此,我的任何同事都可以获取jar,将其添加到他们的项目中,我需要一种方法,使其在业务或实体方法中只需要最少的更改。到目前为止,我所尝试的是,他们所需要做的就是添加一个拦截器类,然后可以使用我的插件库的功能。这样,业务层中唯一需要的更改就是添加一行额外的内容,说明@Interceptor注释和现有的代码库没有被大量修改

还尝试添加em.flush(),但在所述情况下没有帮助。非常感谢您的帮助。

两件事-

1) RollbackException是一个运行时异常,所以catch(异常e)不起作用。你需要像catch(Throwable t)这样的东西来拦截一切

2) 您可以将JMS逻辑放在try块中,这样,如果ctx.procedure()抛出,您就永远不会找到JMS代码

希望这有帮助。

两件事-

1) RollbackException是一个运行时异常,所以catch(异常e)不起作用。你需要像catch(Throwable t)这样的东西来拦截一切

2) 您可以将JMS逻辑放在try块中,这样,如果ctx.procedure()抛出,您就永远不会找到JMS代码


希望这能有所帮助。

我相信这和这个问题是一样的,这个问题也谈到了包装难度
ctx.procedure()
:您所指的帖子中建议的答案需要对业务层代码进行大量修改。我的情况有点不同。我正在编写一个通过拦截器注释添加的可插入模块。业务逻辑来自现有的应用程序代码,我不能(或者更准确地说,我不想)在很大程度上修改。我相信这与这个问题是一样的,这个问题也谈到了包装
ctx.procedure()的困难
:您所指的帖子中的建议答案需要对业务层代码进行大量修改。我的情况有点不同。我正在编写一个通过拦截器注释添加的可插入模块。业务逻辑来自现有的应用程序代码,我不能(或者更准确地说,我不想)在很大程度上修改。这已经有很长时间了,所以感谢您的回答。我还没试过抓住可扔的东西。事实上,我甚至不知道它可以捕获回滚异常。你确定吗?关于#2,我抛出了异常,因此我不认为jms代码会被执行。除非拦截器堆栈在它到达您之前吃掉它,否则您应该能够执行,但由于您在日志中看到它,我认为这是不太可能的。很抱歉这么晚才回复,但我的尝试失败了。回滚异常仅在jpa尝试提交后生成。此外,似乎很难捕捉到特定的jpa异常……这已经是很长时间了,所以感谢您的回答。我还没试过抓住可扔的东西。事实上,我甚至不知道它可以捕获回滚异常。你确定吗?关于#2,我抛出了异常,因此我不认为jms代码会被执行。除非拦截器堆栈在它到达您之前吃掉它,否则您应该能够执行,但由于您在日志中看到它,我认为这是不太可能的。很抱歉这么晚才回复,但我的尝试失败了。回滚异常仅在jpa尝试提交后生成