文章目录
AOP思想
AOP:面向切面编程,核心思想就是解耦。将每个方法/类中通用的逻辑剥离出来,封装成一个独立的模块,在程序运行期间自动将这些逻辑加入到业务代码中(织入)。从而实现业务逻辑与非业务逻辑之间的解耦
非业务逻辑包括:日志记录,性能统计,权限校验等一些与业务无关,但每个方法中都包含的逻辑
AOP可以做到在程序运行期间在不修改源代码的基础上对原有方法进行增强
SpringAOP
- 切面:封装通用的非业务逻辑的类
- 连接点:程序运行中所有可以插入切面的方法
- 切入点:实际被拦截的连接点
- 通知/增强:切面插入具体的方法后,所执行的逻辑
- 目标对象:被一个或多个切面所拦截和增强的,包含业务逻辑的原始对象
- 织入:将切面应用到目标对象,并创建代理对象
通知类型
-
@Before:目标方法执行前执行除非这个通知抛出异常,否则不能阻止目标方法的执行
-
@AfterReturning:目标方法执行完成并返回结果后执行执行目标方法内部抛出异常,这个通知不会执行
-
@AfterThrowing:目标方法运行过程中,抛出异常时执行只有发生异常时才能触发,可以指定只拦截特定类型的对象
-
@After:目标方法执行完成并返回结果后执行执行目标方法内部无论是否抛出异常,这个通知都会执行
-
@Around:目标方法前后都会执行java@Around("execution(...)") //只有@Around有这个参数 public Object timeRecord(ProceedingJoinPoint proceedingJoinPoint){ //方法执行前... Object proceed=null; try{ //执行目标方法,并接收返回值 proceed= proceedingJoinPoint.proceed(); }catch (Throwable throwable){ //抛出异常时执行的逻辑... } //方法执行后... return proceed; }
注意:
@Around方法的返回值必须为Object,用于返回原始方法的返回值,否则原始方法执行完毕今后无法获取返回值。- 其他四种通知虽然不能接收ProceedingJoinPoint但是都可以接收一个JoinPoint参数,来获取目标方法的签名、方法名、参数列表等基本信息
执行顺序:

@PointCut
将公共的切点表达式提取出来,用到时直接引用
java
@Pointcut("execution(...)")
public void pt(){}
@Before("pt()")
...
引用其他切面类中的切点定义时,使用全限定类名.方法()名
切面优先级@Order
使用@Order控制不同切面的执行顺序,@Order接收一个整数,值越小,优先级越高。
最高优先级:Ordered.HIGHEST_PRECEDENCE
最低优先级:Ordered.LOWEST_PRECEDENCE
优先级越高,目标方法执行前越先执行,同时目标方法执行后,越后执行

切点表达式
execution()
execution([权限修饰符] 返回值类型 [包名.类名.]方法名(参数类型) [抛出异常类型])
// execution(* com.example.demo..*(..))
*:匹配任意单个元素,任意返回值/类名/方法名..:- 包路径中:当前包及其所有子包
- 参数列表中:任意数量,任意类型的参数
+:放在接口或类名后,表示匹配该类及其所有子类或实现类
@annotation
使用自定义注解+@annotation来描述一些无规则的切入点
-
编写自定义注解
java//表示为方法注解 @Target(ElementType.METHOD) //注解的生命周期 @Retention(RetentionPolicy.RUNTIME) public @interface MyAspect { }@Target常用取值
ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明 ElementType.METHOD: 描述方法
ElementType.PARAMETER: 描述参数
ElementType.TYPE_USE: 可以标注任意类型
@Retention描述注解的生命周期
- RetentionPolicy.SOURCE:表示注解仅存在于源代码中, 编译成字节码后会被丢弃(@Data)
- RetentionPolicy.CLASS:编译时注解. 表示注解存在于源代码和字节码中, 但在运行时会被丢弃
- RetentionPolicy.RUNTIME:运行时注解. 表示注解存在于源代码, 字节码和运行时中
-
使用@annotation切点表达式定义切点,只对@MyAspect生效
java@Before("@annotation(org.en.aop.aspect.MyAspect)") public void before(){ log.info("method before-myaspect"); } -
在需要的方法上使用@MyAspect添加自定义注解
AOP同类内部方法调用失效
在同一个类中,方法A调用带有AOP注解的方法B,B的切面逻辑不会生效。因为是直接调用的目标对象本身,并没有经过代理对象
代理模式
提供一个代理类,在调用方法时不再直接对目标方法进行调用,而是通过调用代理类进行间接调用
- Subject: 业务接口类,抽象类或者接口,用于定义代理类的逻辑
- RealSubject: 业务实现类. 具体的业务执行, 也就是被代理对象.
- Proxy: 代理类. RealSubject的代理.
静态代理
程序运行之前,代理类的.class文件就已经存在
动态代理
不需要针对每个目标对象都创建一个代理对象,将创建代理对象的工作推迟到程序运行时由JVM实现。代理类是在程序运行时动态生成的

