1.AOP简介
-
什么是AOP
- Aspect Oriented Program面向切面编程
- 在不改变原有逻辑上增加额外的功能,比如解决系统层面的问题,或者增加新的功能
-
场景
- 权限控制
- 缓存
- 日志处理
- 事务控制
-
AOP思想把功能分两个部分,分离系统中的各种关注点
- 核心关注点:业务的主要功能
- 横切关注点:非核心、额外增加的功能
-
好处
- 减少代码侵入、解耦
- 可以统一处理横切逻辑
- 方便添加和删除横切逻辑
2.AOP名词解释
- 横切关注点
- 对哪些方法进行拦截,拦截后怎么处理,这些就叫横切关注点
- 比如权限认证、日志、事务
- 通知Advice
- 在特定的切入点上执行的增强处理,有5种通知
- 比如你需要记录日志、控制事务,提前编写好通用的模块,需要的地方直接调用
- 连接点JoinPoint
- 要用通知的地方,业务流程在运行过程中需要插入切面的具体位置
- 一般是方法的调用前后,全部方法都可以是连接点
- 只是概念,没啥特殊
- 切入点Pointcut
- 不能全部方法都是连接点,通过特定的规则来筛选连接点,就是Pointcut,选中哪几个你想要的方法
- 在程序中主要体现为书写切入点表达式(通过通配、正则表达式)过滤出特定的一组JoinPoint连接点
- 过滤出响应的Advice将要发生的JoinPoint地方
- 切面Aspect
- 通常是一个类,里面定义切入点+通知,定义在什么地方、什么时间点、做什么事情
- 通知Advice指明了时间和做的事情(前置、后置等)
- 切入点Pointcut指定在什么地方干这个事情
- web接口设计中,web层–>网关层–>服务层–>数据层,每一层之间也是一个切面,对象和对象、方法和方法之间都是一个个切面
- 目标target
- 目标类,真正的业务逻辑,可以在目标类不知情的条件下增加新的功能到目标类的链路上
- 织入Weaving
- 把切面(某个类)应用到目标函数的过程称为织入
- AOP代理
- AOP框架创建的对象,代理就是目标对象的加强
- spring中的AOP代理可以是JDK动态代理,也可以是CGLiB代理
3.通知Advice类型
-
@Before前置通知:在执行目标方法之前运行
-
@After后置通知:在目标方法运行结束之后
-
@AfterReturning返回通知:在目标方法正常返回值后运行
-
@AfterThrowing异常通知:在目标方法出现异常后运行
-
@Around环绕通知:在目标方法完成前、后做增强处理,环绕通知是最重要的通知类型,像事务、日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint,需要手动执行joinPoint.proceed()
4.切入点表达式
-
切入点表达式
- 除了返回类型、方法名和参数外,其它项都是可选的(修饰符基本都是省略不写)
execution(访问修饰符 返回值类型 包和类方法 (..)) @Pointcut("execution(public * com.gen..*.* (..))")
- 除了返回类型、方法名和参数外,其它项都是可选的(修饰符基本都是省略不写)
-
常见匹配语法
-
*:匹配任何数量字符,单个
-
…:匹配任何数量字符,可以多个;在类型模式中匹配任何数量子包,在方法参数模式中匹配任何数量参数
()匹配无参的方法 (..)匹配任意参数的方法 (*)匹配只接收一个任何类型参数的方法 (*, Integer)匹配接收两个参数的方法,其中第一个参数是任意类型,第二个参数必须是Integer类型
-
5.简单代码示例
package com.gen;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;/*** 日志切面类*/
@Component
@Aspect
public class LogAspect {/*** 切入点*/@Pointcut("execution(public * com.gen..*.* (..))")public void pointCut() {}@Around("pointCut()")public void log(ProceedingJoinPoint joinPoint) {System.out.println("日志记录==>" + joinPoint.getSignature().getName());try {joinPoint.proceed();} catch (Throwable e) {throw new RuntimeException(e);}}
}