文章目录
什么是AOP面向切面编程
Aspect Oriented Program ⾯向切⾯编程,在不改变原有逻辑上增加额外的功能,⽐如解决系统层⾯的问题,或者增加新的功能
场景:权限控制,缓存,⽇志处理,事务控制
AOP思想把功能分两个部分,分离系统中的各种关注点:
1、核心关注点,业务的主要功能
2、横切关注点,⾮核心、额外增加的功能
AOP面向切面编程核心概念
横切关注点
对哪些⽅法进⾏拦截,拦截后怎么处理,这些就叫横切关注点
⽐如:权限认证、⽇志、事物
通知 Advice
在特定的切⼊点上执⾏的增强处理,有5种通知
比如你需要记录日志,控制事务 ,提前编写好通⽤的模块,需要的地⽅直接调用
连接点 JointPoint
要⽤通知的地⽅,业务流程在运⾏过程中需要插⼊切⾯的具体位置,⼀般是⽅法的调用前后,全部⽅法都可以是连接点(只是概念)
切入点 Pointcut
不能全部⽅法都是连接点,通过特定的规则来筛选连接点, 就是Pointcut,选中那⼏个你想要的⽅法。
在程序中主要体现为书写切入点表达式(通过通配、正则表达式)过滤出特定的⼀组
JointPoint连接点
过滤出相应的 Advice 将要发⽣的joinpoint地⽅
切面 Aspect
通常是⼀个类,⾥⾯定义切⼊点+通知,定义在什么地⽅、什么时间点、做什么事情
通知advice指明了时间和做的事情(前置、后置等)
切入点 pointcut 指定在什么地方干这个事情
web接⼝设计中,web层->⽹关层->服务层->数据层,每⼀层之间也是⼀个切⾯,对象和对象,方法和方法之间都是⼀个个切⾯
目标 target
⽬标类,真正的业务逻辑,可以在⽬标类不知情的条件下,增加新的功能到⽬标类的链路上
织入 Weaving
把切⾯(某个类)应⽤到⽬标函数的过程称为织⼊
AOP代理
AOP框架创建的对象,代理就是目标对象的加强
Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理
AOP里面的通知Advice类型
@Before前置通知:在执行目标方法之前运行
@After后置通知:在目标方法运行结束之后
@AfterReturning返回通知:在目标方法正常返回值后运行
@AfterThrowing异常通知:在目标方法出现异常后运行
@Around环绕通知:在目标方法完成前、后做增强处理 ,环绕通知是最重要的通知类型 ,像事务,⽇志等都是环绕通知,注意编程中核心是⼀个ProceedingJoinPoint,需要⼿动执行joinPoint.procced()
面向切面编程实例
用户下单
核心关注点:创建订单
横切关注点:记录⽇志、控制事务
用户观看付费视频
核心关注点:获取播放地址
横切关注点:记录⽇志、权限认证
JoinPoint连接点:addOrder/ fndOrderByld/ delOrder/ updateOrderPointCut
切入点:过滤出那些 joinpoint中哪些目标函数进行切入
Advice 通知:在切入点中的函数上执行的动作,如记录日志、权限校验等
Aspect 切面:有切入点和通知组合而成,定义通知应用到那些切入点
Weaving 织入:把切面的代码应用到目标函数的过程
//⽬标类 VideoOrderService
//⾥⾯每个⽅法都是连接点
//切⼊点是CUD类型的⽅法,R读取的不作为切⼊点
//CRDU全称:增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)
VideoOrderService{
//新增订单
addOrder(){ }
//查询订单
findOrderById(){}
//删除订单
delOrder(){}
//更新订单
updateOrder(){}
}
//权限切⾯类 = 切⼊点+通知
PermissionAspects{
//切⼊点 定义了什么地⽅
@Pointcut("execution(public int net.xdclass.sp.service.VideoOrderService.*(..))")
public void pointCut(){}
//before 通知 表示在⽬标⽅法执⾏前切⼊, 并指定在哪个⽅法前切⼊
//什么时候,做什么事情
@Before("pointCut()")
public void permissionCheck(){
System.out.println("在 xxx 之前执⾏权限校验");
}
....
}
//⽇志切⾯类 = 切⼊点+通知
LogAspect{
//切⼊点 定义了什么地⽅
@Pointcut("execution(public int net.xdclass.sp.service.VideoOrderService.*(..))")
public void pointCut(){}
//after 通知 表示在⽬标⽅法执⾏后切⼊, 并指定在哪个⽅法前切⼊
//什么时候,做什么事情
@After("pointCut()")
public void logStart(){
System.out.println("在 xxx 之后记录⽇志");
}
......
}
AOP切入点表达式
切入点表示式
除了返回类型、⽅法名和参数外,其它项都是可选的 (修饰符基本都是省略不写)
(必填) 访问修饰符 返回值类型(必填) 包和类 ⽅法
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?namepattern(param-pattern) throws-pattern?)
@Pointcut("execution(public int net.xdclass.sp.service.VideoOrderService.*(..))")
常见匹配语法
*
:匹配任何数量字符单个
..
:匹配任何数量字符,可以多个;在类型模式中匹配任何数量子包,在方法参数模式中匹配任何数量参数
()
匹配⼀个不接受任何参数的方法
(..)
匹配⼀个接受任意数量参数的方法
(*)
匹配了⼀个接受⼀个任何类型的参数的方法
(*,Integer)
匹配了⼀个接受两个参数的方法,其中第⼀个参数是任意类型,第⼆个参数必须是Integer类型
举例:
1、任意公共方法:execution(public * *(..))
2、任何⼀个名字以“save”开始的方法:execution(* save*(..))
3、VideoService接⼝定义的任意方法(识别):execution(* net.xdclass.service.VideoService.*(..))
4、在service包中定义的任意方法(识别):execution(* net.xdclass.service.*.*(..))
5、匹配 service 包,子孙包下所有类的所有方法(识别):execution(* net.xdclass.service..*.*(..))