学习视频🎥:https://www.bilibili.com/video/BV1Vf4y127N5
💬概述:Aspect Oriented Programming 面向切面(方面)编程,意思是不通过修改源代码的方式,在主干功能上添加新的功能
🔑作用与目的:利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
🔑AOP底层原理:AOP底层通过动态代理实现,根据有无接口将动态代理分为两种——JDK和CGLIB
❓ 动态代理:代理模式的实现方式之一,即在在内存中形成代理类
finally语句,即不管被增强的方法是否出现异常都会执行🔑基于AspectJ:Spring AOP一般都是基于AspectJ 实现的
💡 AspectJ 不是Spring的组成部分,实际上是对AOP编程思想的一个实践,
🔑切入点表达式:在进行AOP的配置时,需要使用切入点表达(作为属性值)
🔑作用:指定和标识出需要增强的类和方法
🔑语法格式:execution([权限修饰符] [返回类型] [被增强的类的全类名].[被增强的方法名](参数列表));
- 权限修饰符一般用
*代替,表示全部权限修饰符都符合- 返回类型可以省略
- 参数列表用
..代替
🔑案例(用*表示所有)
execution(* com.Key.dao.UserDao.add(..));execution(* com.Key.dao.UserDao.*(..));execution(* com.Key.dao.*.*(..));🔑导入相关jar包:spring-aspects-…jar、com.springsource.net.sf.cglib-…jar、com.springsource.org.aopalliance-…jar、com.springsource.org.aspectj.weaver-…jar
🔑注解方式实现(重点)
① 创建需要被增强的类和方法
② 创建增强类,在类中创建多个方法,通过在方法上添加注解,使每个方法对应不同的通知类型(5种)
💡 以上每个注解中都有一个属性
value,属性值就是切入点表达式,通过切入点表达式精确找到被增强类和方法
@Before:对应前置通知
// 前置通知
@Before(value = "execution(* com.Key.bean.User.add(..))")
public void before() {System.out.printf("增强方法——前置通知");
}
@AfterReturning:对应后置通知(返回通知)
// 后置通知
@AfterReturning(value = "execution(* com.Key.bean.User.add(..))")
public void afterReturning() {System.out.printf("增强方法——后置通知");
}
@Around:对应环绕通知
💡 环绕通知在被增强方法前后都执行,则需要添加一个形参
ProceedingJoinPoint proceedingJoinPoint,然后调用该形参的方法——proceed()执行被增强的方法
// 环绕通知
@Around(value = "execution(* com.Key.bean.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.printf("方法前执行");// 执行被增强的方法proceedingJoinPoint.proceed();System.out.printf("方法后执行");
}
@AfterThrowing:对应异常通知
// 异常通知
@AfterThrowing(value = "execution(* com.Key.bean.User.add(..))")
public void afterThrowing() {System.out.printf("增强方法——异常通知");
}
@After:对应最终通知
// 最终通知
@After(value = "execution(* com.Key.bean.User.add(..))")
public void after() {System.out.printf("增强方法——最终通知");
}
③ 实现通知(增强)的配置
在spring 配置文件中开启组件扫描(使用注解的必须操作)
使用注解创建出被增强类对象以及增强类对象:在对应类上添加@Component注解即可
// 创建被增强类对象
@Component(value = "user")
public class User {// 被增强方法public void add() {System.out.println("被增强方法...");}
}/*+----------------------------------------------------+*/// 创建增强类对象
@Component(value = "userProxy")
public class UserProxy {// 增强方法(前置通知)@Before(value = "execution(* com.Key.bean.User.add(..))")public void before() {System.out.printf("增强方法——前置通知");}
}
使用注解创建代理对象:在增强类上添加@Aspect注解
// 创建增强类对象并创建出对应的代理对象
@Component(value = "userProxy")
@Aspect
public class UserProxy {// 增强方法(前置通知)@Before(value = "execution(* com.Key.bean.User.add(..))")public void before() {System.out.printf("增强方法——前置通知");}
}
开启代理对象
1️⃣. xml 文件配置:先开启aop 名称空间,再使用标签
2️⃣. 使用注解(完全注解开发):创建配置类,在配置类上添加@EnableAspectJAutoProxy,注解中添加proxyTargetClass属性,属性值置为true(默认是false)
@Configuration
@ComponentScan(basePackage = {"com.Key"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringConfig {// code...
}
④ 抽取公共切入点
使用:在增强类中创建一个方法pointCut(),方法上添加@Pointcut注解,注解中添加value属性(可省略),属性值就是抽取出来的公共切入点表达式,将含有公共切入点表达式的增强方法上的表达式都改成pointCut()即可
// 抽取公共切入点
@Pointcut(value = "execution(* com.Key.bean.User.add(..))")
public void pointCut() {// code...
}@After(value = "pointCut()")
public void after() {// code...
}
作用:减少冗余的表达式,而且修改表达式时只需要修改一处即可
⑤ 设置增强类优先级:当有多个增强类对同一个类及其方法进行增强时,需要对每个增强类设置优先级。在每个增强类上添加@Order注解,注解中添加一个整数值,该数值越小优先级越高
// 设置优先级为1的增强类
@Component("uP")
@Aspect
@Order(1)
public class UserProxy {@Beforepublic void before() {System.out.println("增强方法");}
}
🔑xml 文件配置(了解即可)
① 创建被增强类和增强类,以及各自的方法
② 在spring 配置文件中创建被增强类对象和增强类对象
③ 在spring 配置文件中配置切入点:需要先引入aop 名称空间