【SpringBoot 基础系列】接口上注解 AOP 拦截不到场景兼容
在 Java 的开发过程中,面向接口的编程可能是大家的常态,切面也是各位大佬使用 Spring 时,或多或少会使用的一项基本技能;结果这两个碰到一起,有意思的事情就发生了,接口方法上添加注解,面向注解的切面拦截,居然不生效
这就有点奇怪了啊,最开始遇到这个问题时,表示难以相信;事务注解也挺多是写在接口上的,好像也没有遇到这个问题(难道是也不生效,只是自己没有关注到?)
接下来我们好好瞅瞅,这到底是怎么个情况
<!-- more -->
I. 场景复现
这个场景复现相对而言比较简单了,一个接口,一个实现类;一个注解,一个切面完事
1. 项目环境
采用SpringBoot 2.2.1.RELEASE
IDEA
maven
进行开发
添加 aop 依赖
代码语言:txt复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 复现 case
声明一个注解
代码语言:txt复制@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnoDot {
}
拦截切面,下面这段代码来自之前分享的博文 【基础系列】AOP 实现一个日志插件(应用篇)
代码语言:txt复制@Aspect
@Component
public class LogAspect {
private static final String SPLIT_SYMBOL = "|";
@Pointcut("execution(public * com.git.hui.boot.aop.demo.*.*(..)) || @annotation(AnoDot)")
public void pointcut() {
}
@Around(value = "pointcut()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object res = null;
String req = null;
long start = System.currentTimeMillis();
try {
req = buildReqLog(proceedingJoinPoint);
res = proceedingJoinPoint.proceed();
return res;
} catch (Throwable e) {
res = "Un-Expect-Error";
throw e;
} finally {
long end = System.currentTimeMillis();
System.out.println(req "" JSON.toJSONString(res) SPLIT_SYMBOL (end - start));
}
}
private String buildReqLog(ProceedingJoinPoint joinPoint) {
// 目标对象
Object target = joinPoint.getTarget();
// 执行的方法
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
// 请求参数
Object[] args = joinPoint.getArgs();
StringBuilder builder = new StringBuilder(target.getClass().getName());
builder.append(SPLIT_SYMBOL).append(method.getName()).append(SPLIT_SYMBOL);
for (Object arg : args) {
builder.append(JSON.toJSONString(arg)).append(",");
}
return builder.substring(0, builder.length() - 1) SPLIT_SYMBOL;
}
}
然后定义一个接口与实现类,注意下面的两个方法,一个注解在接口上,一个注解在实现类上
代码语言:txt复制public interface BaseApi {
@AnoDot
String print(String obj);
String print2(String obj);
}
@Component
public class BaseApiImpl implements BaseApi {
@Override
public String print(String obj) {
System.out.println("ano in interface:" obj);
return "return:" obj;
}
@AnoDot
@Override
public String print2(String obj) {
System.out.println("ano in impl:" obj);
return "return:" obj;
}
}
测试 case
代码语言:txt复制@SpringBootApplication
public class Application {
public Application(BaseApi baseApi) {
System.out.println(baseApi.print("hello world"));
System.out.println("-----------");
System.out.println(baseApi.print2("hello world"));
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
执行后输出结果如下(有图有真相,别说我骗你