Spring AOP:如何排除由于其他人@Pointcuts/advices 执行而导致的不必要的@Pointcut(@Around 建议)执行 [英] Spring AOP: How exclude an unnecessary @Pointcut (@Around advice) execution due the execution from others @Pointcuts/advices

查看:49
本文介绍了Spring AOP:如何排除由于其他人@Pointcuts/advices 执行而导致的不必要的@Pointcut(@Around 建议)执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在与:

  • Spring 框架 4.3.3
  • AspectJ 1.8.9
  • Spring Framework 4.3.3
  • AspectJ 1.8.9

我有以下正常流程:

  • @Controller -> @Service -> @Repository
  • @Controller -> @Service -> @Repository

我有以下关于 AOP 的一对:

I have the following pair about AOP:

  • PersonaServicePointcut
    • PersonaServiceAspect

    场景如下:

    @Service 类有一些方法,例如:deletesaveupdatefindOneById.它们在同一个类中一起声明.

    The @Service class has some methods such as: delete, save, update and findOneById. They are declared together within the same class.

    对于诸如 deleteupdateAOP 之类的方法,我使用的是 @Before@Around 建议调用 findOneById 方法.

    For the methods such as delete and update through AOP I am using a @Before or @Around advice to call the findOneById method.

    原因是如果实体不存在,执行deleteupdate 方法(考虑Rest 场景)是没有意义的.因此,通过 advice 必须抛出异常,比如说异常 A,它必须在 @ControllerAdvice

    The reason is that does not make sense execute the delete or update methods (consider Rest scenario) if the entity does not exist. Therefore through that advice an exception must be throw, lets say Exception A, it must be handled in a @ControllerAdvice

    对于 save 方法实际上已经应用了相同的方法.因此在执行 save 方法other @Before@Around 之前,建议是再次调用 findOneById 方法.如果实体已经存在,则必须抛出异常,比如说异常 B,它必须在 @ControllerAdvice

    Practically the same approach for the save method has been applied. Therefore before to execute the save method other @Before or @Around advice is executed calling the findOneById method again. If the entity already exists an exception must be thrown, lets say Exception B, it must be handled in a @ControllerAdvice

    请注意,我有 3 点/3 条建议使用 findOneById 方法.用于检查实体是否存在.

    Observe I have 3 points/3advices that use the findOneById method. It to check if exists an entity or not.

    例如:

        @Pointcut(value=
        "execution(* mypackage.PersonaServiceImpl.saveOne(otherpackage.Persona)) 
        && args(persona)")
        public void saveOnePointcut(Persona persona){}
    
        @Pointcut(value=
        "execution(*  
        mypackage.PersonaServiceImpl.updateOne(otherpackage.Persona)) 
        && args(persona)")
        public void updateOnePointcut(Persona persona){}
    
        @Pointcut(value="execution(*  
        mypackage.PersonaServiceImpl.deleteOne(String)) && args(id)")
        public void deleteOnePointcut(String id){}
    

    同样:这 3 个通知使用或执行findOneById 方法.

    Again: these 3 advices use or execute the findOneById method.

    问题是当我添加一个新的切入点时,例如:

    The problem is when I add a new pointcut such as:

    @Pointcut(value="execution(*    
    mypackage.PersonaServiceImpl.findOneById(String)) 
    && args(id)")
    public void findOneByIdPointcut(String id){}
    

    我创建了这个切入点来检查一个实体是否已经存在,如果它不存在,它必须抛出一个 C 类型的异常(它用于经典的 404).

    I have created this pointcut to check if an entity already exists or not, if it does not exist it must throw an exception of type C (it for the classic 404).

    通过@Before@Around 建议为 提供执行findOneById 方法似乎是多余的findOneById 方法本身.但是我需要它来loggingaudit 目的,并创建C 类型的异常.它必须由某些 @ControllerAdvice

    Seems redundant execute the findOneById method through a @Before or @Around advice for the findOneById method itself. But I need this to logging and audit purposes and to create the exception of type C too. It must be handle by some @ControllerAdvice

    问题是当其他对delete/update/save方法的建议被执行时(记住它们调用并执行>findOneById 方法)我的 findOneByIdPointcut不必要地执行.

    The problem is when the others advices for the delete/update/save methods are executed (remember they call and execute the findOneById method too) my findOneByIdPointcut is executed unnecessarily.

    我需要更改切入点声明以指示如下内容:

    I need change the pointcut declaration to indicate something like this:

    @Pointcut(Alpha)
    public void findOneByIdPointcut(String id){}
    

    Alpha 在哪里:

    @ServicefindOneById 方法执行 before/around 建议,但是永远不要如果它已经从
    的其他人的建议中调用了PersonaServiceAspect 类.

    execute the before/around advice for the @Service's findOneById method, but never if its call has been done from the others advices from the
    PersonaServiceAspect class.

    我尝试了很多方法来使用 !execution!within 组合,但没有结果.

    I've tried many ways with !execution and !within combinations, but no results.

    即使我只创建了一个切入点,拦截所有@Service 的方法及其各自独特的 @Around 建议,并通过 ProceedingJoinPointprocedingJoinPoint 参数,我可以检查调用了什么方法,然后执行相应的控制.但是这种行为又发生了.

    Even when I have created just one Pointcut that intercepts all the @Service's methods with its respective unique @Around advice, and through the ProceedingJoinPoint proceedingJoinPoint parameter I am able to check what method has been called and then do the respective controls. But again this behaviour happens.

    这意味着,通过以下:

    @Around("PersonaServicePointcut.anyMethodPointcut()")
        public Object aroundAdviceAnyMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
    

    其中 anyMethodPointcutexecution(* mypackage.PersonaServiceImpl.*(..))

    有可能实现这种方法吗?怎么样?

    Is possible accomplish this approach? How?

    谢谢.

    推荐答案

    您可以使用

    !cflow(<pointcut>)
    

    在您的示例中,您希望排除 findOneById 的那些执行,其中执行位于您自己的通知的控制流内.如果您的建议应用于切入点表达式

    In your example, you want to exclude those executions of the findOneById where the execution is inside the control flow of your own advice. If your advice is applied to the pointcut expression

    @Pointcut("saveOnePointcut() || updateOnePointcut() || deleteOnePointcut()")
    public void combinedPointcut() {}
    

    您可以通过以下方式排除:

    you can exclude that with:

    !cflow(combinedPointcut())
    

    或者简单地从所有通知执行的控制流中排除所有控制流,您可以使用:

    or to simply exclude all control flows from within the control flow of all advice executions, you could use:

    !cflow(adviceexecution())
    

    基于组合的切入点表达式,您的周围查找建议如下所示:

    Your around find advice would look like this, based on the combined pointcut expression:

    @Around("findOneByIdPointcut() && !cflow(combinedPointcut())")
    public void aroundFind() {
        ....
    }
    

    请注意,您不能在示例中组合切入点表达式,因为它们绑定了切入点参数.您需要删除 &&args(...) 部分并将它们直接移动到通知切入点表达式.您不能将诸如 args(paramName) 之类的绑定切入点表达式与 ||(或)运算符结合使用,因此您需要为这些情况创建单独的建议.如果您愿意,您仍然可以将这些通知中的大部分工作委托给一个方法.在此处查看此类委托的示例.

    Note that you can't combine the pointcut expressions in your example because they're binding pointcut arguments. You need to remove the && args(...) parts and move them to the advice pointcut expressions directly. You can't combine binding pointcut expressions like args(paramName) with the || (or) operator so you'll need to create separate advices for those cases. You can still delegate most of the work from those advices to a single method if you want to. See an example of this kind of delegation here.

    这篇关于Spring AOP:如何排除由于其他人@Pointcuts/advices 执行而导致的不必要的@Pointcut(@Around 建议)执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆