Spring的bean()切入点在使用OR语句时无法正常工作。

huangapple go评论110阅读模式
英文:

Spring bean() pointcut doesn't work with OR statement

问题

我正在使用Spring特定的切点表达式bean()。对于以下表达式,只有左侧部分被捕获:

@AfterReturning("bean(FirstService).firstMethod(..) || bean(SecondService).secondMethod(..)")

如果我反过来写,同样只有左侧部分被捕获:

@AfterReturning("bean(SecondService).secondMethod(..) || bean(FirstService).firstMethod(..)")

如果我这样写:

@AfterReturning("bean(SecondService).secondMethod(..)")
和
@AfterReturning("bean(FirstService).firstMethod(..)")

分别在两个方法中,

两者都能正常工作。
第一个OR语句有什么问题?

英文:

I am using Spring specific pointcut expression called bean(). For the following expression only the left part is being catched:

@AfterReturning("bean(FirstService).firstMethod(..) || bean(SecondService).secondMethod(..)")

if I do reverse, again the left part is being catched:

@AfterReturning("bean(SecondService).secondMethod(..) || bean(FirstService).firstMethod(..)")

If i write:

@AfterReturning("bean(SecondService).secondMethod(..)")

and @AfterReturning("bean(FirstService).firstMethod(..)") in two methods

then both works.
What's wrong with the first OR statement ?

答案1

得分: 4

这个点切表达式不能按预期工作的原因是因为它是错误的。Spring框架对此没有抛出任何异常,这也是导致混淆的另一个原因。

根据Spring参考文档的第 5.4.3节 声明切点,声明bean()切点指示器的正确方式如下:

bean(idOrNameOfBean)

idOrNameOfBean 标记可以是任何Spring bean的名称。

以下代码所示的切面是定义切面的正确方式,它将拦截两个bean的所有方法调用。

@Component
@Aspect
public class BeanAdviceAspect {

	@AfterReturning("bean(firstService) || bean(secondService)")
	public void logMethodCall(JoinPoint jp) {
		System.out.println(jp.getSignature());
	}
}

点切表达式 bean(firstService).firstMethod() 是错误的,框架似乎会忽略 bean(firstService) 后面的任何内容,这就是在声明反转时你的测试用例行为不同的原因。

为了确认这种行为,以下切面

@Component
@Aspect
public class BeanAdviceAspect {

	@AfterReturning("bean(firstService).firstMethod() || bean(secondService)")
	public void logMethodCall(JoinPoint jp) {
		System.out.println(jp.getSignature());
	}
}

也会通知一个方法 firstService.thirdMethod(),原因如上所述。

另一种声明 bean 切点指示器的方式如下。这匹配与通配符表达式匹配的任何Spring bean名称中的方法执行。

@AfterReturning("bean(*Service)")
public void logMethodCall(JoinPoint jp) {
	System.out.println(jp.getSignature());
}

希望对你有所帮助。

英文:

The reason for this point cut expression to not work as expected is because it is incorrect. The Spring framework is not throwing any exception for this is another
reason that leads to confusion.

As per the Spring Reference Documentation Section 5.4.3. Declaring a Pointcut the correct way to declare a bean() pointcut designator is as follows

> bean(idOrNameOfBean)
>
> The idOrNameOfBean token can be the name of any Spring bean. .

An aspect like the following code is the correct way to define the aspect and this will intercept all the method calls for both beans .

@Component
@Aspect
public class BeanAdviceAspect {

	@AfterReturning("bean(firstService) || bean(secondService)")
	public void logMethodCall(JoinPoint jp) {
		System.out.println(jp.getSignature());
	}
}

A point cut expression bean(firstService).firstMethod() is incorrect and the framework seems to discard anything after the bean(firstService) and that is the reason your testcases behaves differently when the declaration is reversed.

To confirm this behaviour , the following aspect

@Component
@Aspect
public class BeanAdviceAspect {

	@AfterReturning("bean(firstService).firstMethod() || bean(secondService)")
	public void logMethodCall(JoinPoint jp) {
		System.out.println(jp.getSignature());
	}
}

would also advice a method firstService.thirdMethod() for the reasons explained above.

Another way to declare bean pointcut designator is as follows . This matches the method execution in any Spring beans names that matches the wildcard expression.

@AfterReturning("bean(*Service)")
public void logMethodCall(JoinPoint jp) {
	System.out.println(jp.getSignature());
}

Hope this helps

huangapple
  • 本文由 发表于 2020年3月16日 23:09:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/60708456.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定