Spring AOP:如何排除由于其他@ Pointcuts/advices执行而不必要的@Pointcut(@Around建议)执行 [英] Spring AOP: How exclude an unnecessary @Pointcut (@Around advice) execution due the execution from others @Pointcuts/advices
问题描述
我正在与
-
Spring Framework
4.3.3 -
AspectJ
1.8.9
Spring Framework
4.3.3AspectJ
1.8.9
我有以下正常流程:
-
@Controller
->@Service
->@Repository
@Controller
->@Service
->@Repository
关于AOP
,我有以下几对:
-
PersonaServicePointcut
-
PersonaServiceAspect
PersonaServicePointcut
PersonaServiceAspect
情况如下:
@Service
类具有一些方法,例如:delete
,save
,update
和findOneById
.在同一类中将它们声明为一起.The
@Service
class has some methods such as:delete
,save
,update
andfindOneById
. They are declared together within the same class.对于诸如
delete
和update
到AOP
的方法,我正在使用@Before
或@Around
建议来调用findOneById
方法.For the methods such as
delete
andupdate
throughAOP
I am using a@Before
or@Around
advice to call thefindOneById
method.原因是,如果该实体不存在,则 execute
delete
或update
方法(考虑Rest场景)没有意义.因此,必须通过advice
引发异常,比如说 A 异常,必须在@ControllerAdvice
The reason is that does not make sense execute the
delete
orupdate
methods (consider Rest scenario) if the entity does not exist. Therefore through thatadvice
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 thesave
method other@Before
or@Around
advice is executed calling thefindOneById
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).似乎冗余 execute
findOneById
方法.但是,我出于logging
和audit
的目的,并创建类型 C 的例外,也需要这样做.它必须由某些@ControllerAdvice
Seems redundant execute the
findOneById
method through a@Before
or@Around
advice for thefindOneById
method itself. But I need this tologging
andaudit
purposes and to create the exception of type C too. It must be handle by some@ControllerAdvice
问题是在执行其他有关
delete/update/save
方法的建议时(请记住它们也调用并 executefindOneById
方法)我的findOneByIdPointcut
是不必要地执行.The problem is when the others advices for the
delete/update/save
methods are executed (remember they call and execute thefindOneById
method too) myfindOneByIdPointcut
is executed unnecessarily.我需要更改切入点声明以指示类似以下内容:
I need change the pointcut declaration to indicate something like this:
@Pointcut(Alpha) public void findOneByIdPointcut(String id){}
Alpha
所在的位置:对
@Service
的findOneById
方法执行先行/前后建议,但 从不(如果已从其他<
PersonaServiceAspect
类.execute the before/around advice for the
@Service
'sfindOneById
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
建议,并且通过ProceedingJoinPoint proceedingJoinPoint
参数,我可以检查调用了哪种方法,然后进行各自的控制.但是,这种行为再次发生.Even when I have created just one Pointcut that intercepts all the
@Service
's methods with its respective unique@Around
advice, and through theProceedingJoinPoint proceedingJoinPoint
parameter I am able to check what method has been called and then do the respective controls. But again this behaviour happens.这意味着通过以下方式:
It means, through the following:
@Around("PersonaServicePointcut.anyMethodPointcut()") public Object aroundAdviceAnyMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
其中
anyMethodPointcut
是execution(* mypackage.PersonaServiceImpl.*(..))
是否可以实现这种方法?怎么样?
Is possible accomplish this approach? How?
谢谢.
推荐答案
您可以通过以下方式在切入点表达式的控制流中排除切入点:
You can exclude pointcuts within the control flow of a pointcut expression with
!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() {}
您可以使用:
!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 likeargs(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屋!
-