AOP
一、AOP简介
1.什么是AOP?
Aspect Oriented Programmig(面向切面编程),是一种指导如何组织程序结构的编程思想。
2.作用
在不改变源代码的基础上进行功能增强。
3.几个概念
(1)连接点(JoinPoint)
程序执行过程中的任意位置,可以是执行方法、抛出异常、设置变量等。在Spring中,可以将连接点理解为某个方法的执行。
(2)切入点(Pointcut)
是匹配连接点的式子,在SpringAop中,一个切入点可以只描述一个具体方法,也可以匹配多个方法。
(3)通知(Advice)
在切入点执行的操作(共性功能),在Spring中这个操作最终以方法的形式呈现。
【tips】通知类:定义通知的类。
(4)切面(Aspect)
描述通知与切入点的对应关系,不然多个通知不知该对应哪个切入点了。
二、AOP的使用(使用注解开发AOP)
1.导坐标
(1)spring-aop(随spring-context已自动导入)
(2)aspectjweaver
2.定义连接点方法(即原始操作)
3.创建共性功能(通知类与通知)
(1)在SpringConfig配置类中声明使用注解开发AOP(@EnableAspectJ***)
(2)定义通知类,将其定义为Bean(@Component),并声明该类为切面类(@Aspect)
(3)定义通知(即方法)
4.定义切入点(★)
(1)定义一个私有“空”方法
切入点的定义依托一个无实际意义的“三无”私有方法,即无参数、无返回值、方法体无逻辑。
(2)定义切入点(@Pointcut)
切入点是一个位置,即运行到哪里需要加功能(即通知)。
5.绑定通知与切入点的对应关系(@Before)
三、AOP的工作流程
1.Spring容器启动
2.读取切入点
读取所有切面配置中的切入点,即与切面绑定的切入点,没绑定的不读取。
3.初始化Bean,判断切入点是否被匹配
初始化Bean,判断Bean对应的类中的方法是否能匹配到切入点:
(1)匹配失败:创建Bean对象,继续4.(1);
(2)匹配成功:创建原始对象(目标对象)的代理对象,继续4.(2)。
【tips】SpringAOP的本质:整个AOP的实现就是通过代理模式来实现的。
4.获取Bean,执行方法
(1)获取Bean,调用方法并执行,完成操作;
(2)获取的Bean是代理对象,根据代理对象的运行模式运行原始方法与增强的内容,完成操作。
【tips】①目标对象(Target):使用AOP时,最终是代理对象在运行,被这个代理对象所代理的原始对象,称为目标对象。
②代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象来实现。
四、AOP切入点表达式
1.语法格式
切入点表达式标准格式:动作关键字(访问修饰符 返回值类型 包名.类/接口名.方法名(参数)异常名)
(1)动作关键字:描述切入点的动作行为,如execution表示执行到指定切入点
(2)访问修饰符:public,private等,可忽略
(3)异常名:方法定义中抛出指定异常,可忽略
2.通配符★
(1)*:单个独立的任意符号,可单独出现,也可以作为前缀或后缀的匹配符出现
(2)..:多个连续的任意符号,常用于简化包名和参数的书写
(3)+:专用于匹配子类类型
3.书写技巧
(1)描述切入点通常描述接口,而不描述其实现类;
(2)包名描述尽量不使用..匹配,效率过低,常用*做单个包描述匹配或精准匹配;
(3)接口名/类名书写名称与模块相关的采用*匹配,如UserService描述成*Service;
(4)方法名书写动词采用精准匹配,如selectAll就写成selectAll;名词采用*匹配,如getById写成getBy*。
五、AOP通知类型
AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加入到响应的位置。
1.前置通知@Before
2.后置通知@After
3.环绕通知★@Around
需要有一个对原始操作的调用来区分前后:
【注意事项】
4.返回后通知@AfterReturning
5.抛出异常后通知@AfterThrowing
六、ProceedingJoinPoint的使用
1.获取执行签名信息
Signature signature = pjp.getSignature();
2.通过签名获取执行类型(接口名)
String className = signature.getDeclaringTypeName();
3.通过签名获取执行操作名(方法名)
String methodName = signature.getName();
【输出结果】:System.out.println(className+"业务层接口"+methodName+"万次执行时间:" + (end - start) + "ms"); //com.service.AccountService业务层接口findAll万次执行时间:2053ms
七、AOP通知获取原始操作的数据
1.获取原始操作的参数
(1)@Before和@After获取参数
用JoinPoint的getArgs方法。JoinPoint对象描述了连接点方法的运行状态,可以获取原始方法的调用参数。
(2)@Around获取参数
用ProceedingJoinPoint(是JoinPoint的子类)的getArgs方法。
2.获取原始操作的返回值
只有@Around和@AfterReturning能获取返回值。
(1)@Around获取返回值
(2)@AfterReturning获取返回值
先定义一个用来接收返回值的形参,并在@AfterReturning中用returing属性声明接收返回值的形参。
3.获取原始操作的异常
只有@Around和@AfterThrowing能获取返回值。
(1)@Around获取异常
直接try...catch...
(2)@AfterThrowing获取异常
先定义一个用来接收异常的形参,并在@AfterThrowing中用throwing属性声明接收异常的形参。