理解别人远比审判别人更为快乐。
问题描述
因业务功能需要,在service层中,有些方法使用了自定义注解。
最近,在Spring 中使用自定义注解时,发现了一个现象。
如果只有一个 service 层使用的话,是一点问题都没有的。比如说:
ControllerA#MethodA — 调用 —》 ServiceA#MethodA
但是如果在Service层中调用了两个拥有自定义注解的,就会有自定义注解失效。
例:
// ========== Controller Start ==========
/**
* Controller 层
* 省略类定义、自动注入等代码
*/
@RequestMapping("/example")
void example(){
exampleService.example();
}
@RequestMapping("/depend")
void depend(){
exampleService.depend();
}
// ========== Service End ==========
// ========== Service Start ==========
/**
* Service 层
* 实现类的方法,省略无关的代码块
*/
@MyAop
@Override
void example(){
depend();
// 一些其他操作
}
@MyAop
@Override
void depend(){
// 一些业务处理
}
// ========== Service End ==========
在示例代码中,@MyAop
是自定义的aop切面,可以实现业务上的功能。
如果在Controller 层 调用 depend 方法,MyAop 可以正常使用,但是如果在Controller 层调用example,则 depend() 执行时,@MyAop 不生效。
解决方案
不在同类中调用
将 depend 抽出,移动到其他类可以解决此问题 (推荐此方式):
// ========== Example Service Start ==========
@MyAop
@Override
void example(){
dependService.depend();
// 一些其他操作
}
// ========== Example Service Start ==========
// ========== Depend Service Start ==========
@MyAop
@Override
void depend(){
// 一些业务处理
}
// ========== Depend Service Start ==========
基于容器
但也有可能说,depend() 方法就是要求在当前类中,和 example() 在同一类里。
这样的话,是不是就没有解决方案了呢?
当然不是,可以用这种方式解决:
((ExampleService) AopContext.currentProxy()).depend();
原因 1
Spring AOP 是基于代理的。
这里要了解的关键是,类方法中的客户端代码具有对代理的引用。也就是说,对该对象引用方法的调用就是对代理的调用。
所以,如果同函数中有其他方法调用,则意味着都将是针对 该引用而不是代理调用。
最终的结果则是: 自调用不会让和方法调用相关的aop执行。
PS
如果有任何问题或补充内容,欢迎在下方留言。
参考地址:
[1] Spring Core Technologies https://docs.spring.io/spring-framework/docs/5.3.10-SNAPSHOT/reference/html/core.html#aop-api