Spring boot中使用aop
-
导入pom的坐标
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
在application.yml中增加配置项
spring: aop: auto: true proxy-target-class: true
proxy-target-class 这个值默认是false 是标准JDK基于接口的代理将起作用 是代理接口
设置为true时 是基于累的代理(cglib库)
被拦截的方法 该方法所在的类必须已经注入到spring容器中
@Component
class Test {
public void test1() {
...
}
}
-
切面类
- 类上要写明注解 @Aspect
@Aspect class myAop { @After("execution(* com.xxxx.xxxx.xxx.service.xxx.test1(..))") 注意根据配置写接口还是写类 类代理之后接口和类都生效 public void xxx(JoinPoint jp) throws AppException { Object[] args = jp.getArgs(); args 可以获取到拦截的那个类的参数 和 所有你想要获得的接口 例如代理上边的那个类 是这样写 String id = ((String[])args[0])[0]; 这样就获得了传入的参数 } }
以上aop的最少基本步骤已经完成。
总结一些特例
-
当被代理的方法是内部直接调用的时候 无法通过上边的形式拦截,需要改被代理类的写法 官方的意思是写两个类 但是可能实际情况不被允许分到两个类里
@Component class Test { public void test2() { test1(); } public void test1() { ... } } 如以上写法内部调用的时候aop无法生效
解决办法
首先在类上标记开启动态代理 @EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true) 然后调用test1的时候要这么写 if (null != AopContext.currentProxy()) { ((xxxService)AopContext.currentProxy()).test1(id); } else { test1(id); }
-
如果用的mybait里的一些delete或者add方法,如果是父类的方法,就会代理不到。
例如 tk.mybaits里的类继承 我们直接使用 xxxService.delete(id) 这个delete是父类的方法 这个时候是代理不到的
解决方法 在类上边加上target标注的更明确一点,并且需要在类里重写下父类
@After("execution(* com.xxx.xxx.base.common.base.*.deleteById(..)) target(com.xx.xx.xx.xx.service.xxxServiceImpl)")