一,execution切入点表达式
//execution主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配, execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
?的部分是可以省略的,不建议省略包名和类名 异常是定义方法时的异常
1.表达式的通配符
*
:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
..
:多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数//同时匹配两个方法 @Around("execution(* com.itheima.service.BookService.save()) ||" + "execution(* com.itheima.service.BookService.update(..))")
!!!! 可以使用 且&& 或|| 非! 来组合比较复杂的表达式
二,@annotation 切入点表达式
1,使用方式
一)自定义注解
@Target(ElementType.METHOD) //表示该注解在什么地方生效 @Retention(RetentionPolicy.RUNTIME) //该注解什么时候运行 public @interface MyLog { }
二)在切面类方法上的切面表达式中协商自定义注解类的全类名
@Slf4j @Component @Aspect public class MyAspect6 { //针对list方法、delete方法进行前置通知和后置通知 //前置通知 @Before("@annotation(com.itheima.anno.MyLog)") public void before(){ log.info("MyAspect6 -> before ..."); } //后置通知 @After("@annotation(com.itheima.anno.MyLog)") public void after(){ log.info("MyAspect6 -> after ..."); } }
三)在业务方法上加上注解
@Slf4j @Service public class DeptServiceImpl implements DeptService { @Autowired private DeptMapper deptMapper; @Override @MyLog //自定义注解(表示:当前方法属于目标方法) public List<Dept> list() { List<Dept> deptList = deptMapper.list(); //模拟异常 //int num = 10/0; return deptList; } @Override @MyLog //自定义注解(表示:当前方法属于目标方法) public void delete(Integer id) { //1. 删除部门 deptMapper.delete(id); } @Override public void save(Dept dept) { dept.setCreateTime(LocalDateTime.now()); dept.setUpdateTime(LocalDateTime.now()); deptMapper.save(dept); } @Override public Dept getById(Integer id) { return deptMapper.getById(id); } @Override public void update(Dept dept) { dept.setUpdateTime(LocalDateTime.now()); deptMapper.update(dept); } }
三,连接点
------什么是连接点----就是可以被AOP控制的方法
在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint类型
对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint的父类型
1,获取当前方法对象的信息
//环绕通知 @Around("pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { //获取目标类名 String name = pjp.getTarget().getClass().getName(); log.info("目标类名:{}",name); //目标方法名 String methodName = pjp.getSignature().getName(); log.info("目标方法名:{}",methodName); //获取方法执行时需要的参数 Object[] args = pjp.getArgs(); log.info("目标方法参数:{}", Arrays.toString(args)); //执行原始方法 Object returnValue = pjp.proceed(); return returnValue; }