什么是 AOP
面向切面编程。
利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的 耦合度 降低,提高程序的可重用性,同时提高了开发的效率。
AOP 底层原理
AOP 底层使用了 动态代理
- 有接口情况 使用的是 JDK 动态代理
- 没有接口情况 使用的是 CGLIB 动态代理
编写 JDK 动态代理代码
//(1)创建接口,定义方法 public interface UserDao { public int add(int a,int b); public String update(String id); } //(2)创建接口实现类,实现方法 public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { return a+b; } @Override public String update(String id) { return id; } }
AOP 术语
- 连接点
类里面的哪些方法可以被增强,这些方法就叫做 连接点。
- 切入点
实际被真正增强的方法,称为 切入点。
- 通知(增强)
- 实际增强的逻辑部分称为 通知(增强)。
- 通知有多种类型:
- 前置通知
- 后置通知 (有异常这个不会执行的)
- 环绕通知
- 异常通知
- 最终通知
- 切面(切入点+额外功能)
指的是 动作,把通知应用到切入点的过程。
Spring 基于 AspectJ 框架实现 AOP 操作。
基于注解使用 AOP
切入点表达式
- 切入点表达式作用: 知道对哪个类里面的哪个方法进行增强
- 语法结构:execution([权限修饰符] [返回类型] [类全路径] [方法名称][参数列表])
举例1: 对 com.snow.dao.BookDao 类里面的 add 进行增强
execution(* com.snow.dao.BookDao.add(…))
举例 2:对 com.snow.dao.BookDao 类里面的所有的方法进行增强
execution(* com.snow.dao.BookDao.* (…))
举例 3:对 com.snow.dao 包里面所有类,类里面所有方法进行增强
execution(* com.snow.dao.. (…))
也可以这样:
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult") public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) { handleLog(joinPoint, controllerLog, null, jsonResult); }
@Aspect
标注在类上面,表示切面类
@Around
ProceedingJoinPoint
实操
创建 被增强的类 和 被增强的方法
@Component public class User { // 被增强的方法 public void add() { System.out.println("add......."); } }
创建 增强类 和 增强方法
//增强的类 @Component @Aspect // 生成代理对象 public class UserProxy { //前置通知 //@Before 注解表示作为前置通知 @Before(value = "execution(* com.snow.spring5.aopanno.User.add(..))") public void before() { System.out.println("before........."); } //后置通知(返回通知):有异常不会执行这个的 @AfterReturning(value = "execution(* com.snow.spring5.aopanno.User.add(..))") public void afterReturning() { System.out.println("afterReturning........."); } //最终通知:不管有没有异常 都会执行 @After(value = "execution(* com.snow.spring5.aopanno.User.add(..))") public void after() { System.out.println("after........."); } //异常通知 @AfterThrowing(value = "execution(* com.snow.spring5.aopanno.User.add(..))") public void afterThrowing() { System.out.println("afterThrowing........."); } //环绕通知 @Around(value = "execution(* com.snow.spring5.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前........."); //被增强的方法执行 proceedingJoinPoint.proceed(); System.out.println("环绕之后........."); } }
优化——相同的切入点做一个提取:
//相同切入点抽取 @Pointcut(value = "execution(* com.snow.spring5.aopanno.User.add(..))") public void pointdemo() { } //前置通知 @Before(value = "pointdemo()") public void before() { System.out.println("before........."); } //最终通知 @After(value = "pointdemo()") public void before() { System.out.println("after........."); }
有多个增强类多同一个方法进行增强,设置增强类优先级
(1)在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
@Component @Aspect @Order(1) public class PersonProxy