javaWeb开发之AOP
1.AOP
是面向切面编程就是面向特定方法编程
AOP的优势主要体现在以下四个方面:
减少重复代码:不需要在业务方法中定义大量的重复性的代码,只需要将重复性的代码抽取到AOP程序中即可。
代码无侵入:在基于AOP实现这些业务功能时,对原有的业务代码是没有任何侵入的,不需要修改任何的业务代码。
提高开发效率
维护方便
2.AOP基础
入门案例:
需求:统计部门管理各个业务层方法执行耗时
原始方式代码示例:
需要执行业务层的每一个方法,获取方法运行的开始时间; 然后运行原始的方法逻辑; 最后在每一个方法运行结束时,获取方法运行结束时间,计算执行耗时。

SpringAOP实现:
导入AOP依赖:

编写AOP程序:针对于特定方法根据业务需要进行编程

重新启动SpringBoot服务,打开浏览器访问部门管理的功能进行测试
AOP常见的应用场景:
记录系统的操作日志;权限控制;事务管理
2.AOP核心概念
连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
通知:Advice,指那些重复的逻辑,也就是共性功能(最终体现为一个方法)
切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
目标对象:Target,通知所应用的对象


所定义的通知是如何与目标对象结合在一起:
底层是基于动态代理技术来实现的,在程序运行的时候,会自动的基于动态代理技术为目标对象生成一个对应的代理对象。在代理对象当中就会对目标对象当中的原始方法进行功能的增强。
动态代理:

3.AOP进阶
通知类型:
根据通知方法执行时机的不同,将通知类型分为以下常见的五类:
@Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
@Before:前置通知,此注解标注的通知方法在目标方法前被执行
@After:后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行@AfterReturning:返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行@AfterThrowing:异常后通知,此注解标注的通知方法发生异常后执行
通过代码加深理解:


无报错情况下,@AfterThrowing标识的通知方法不会执行
报错情况下,@AfterReturning标识的通知方法不会执行,@AfterThrowing标识的通知方法执行了
@Around环绕通知中原始方法调用时有异常,通知中的环绕后的代码逻辑也不会在执行了
解决切入点表达式重复的问题:抽取,用注解@PointCut
@PointCut:将公共的切入点表达式抽取出来,需要用到时引用该切入点表达式即可

注:当切入点方法使用private修饰时,仅能在当前切面类中引用该表达式;public:在其他外部的切面类中也可以引用该表达式
通知顺序:
定义两种类型的通知进行测试,一种是前置通知@Before,一种后置通知@After
定义多个切面类:



启动程序
执行顺序:在不同切面类中,默认按照切面类的类名字母排序
目标方法前的通知方法:字母排名靠前的先执行;目标方法后的通知方法:字母排名靠前的后执行
想控制执行顺序方式:修改切面类的类名(繁琐,不推荐);使用Spring提供的@Order注解

4.切入点表达式
作用:主要用来决定项目中的哪些方法需要加入通知
常见形式:
execution(……):根据方法的签名来匹配

@annotation(……):根据注解匹配

execution表达式:
主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配
语法:
execution(访问修饰符?返回值包名.类名.?方法名(方法参数)throws异常?)
其中带?的表示可以省略的部分:
访问修饰符:可省略(比如:public、protected)
包名.类名:可省略
throws异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
可以使用通配符描述切入点:
.*:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
![]()
..:多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数

切入点表达式的语法规则:

@annotation表达式:
用于匹配标识有特定注解的方法。
实现步骤:
编写自定义注解

在业务类要做为连接点的方法上添加自定义注解

切面类

execution切入点表达式与@annotation切入点表达式的应用场景 :
如果execution切入点表达式方便描述指定的方法,就使用execution表达式
否则,就使用@annotation切入点表达式
5.AOP案例
需求:将案例(Tlias智能学习辅助系统)中增、删、改相关接口的操作日志记录到数据库表中
操作日志信息包含:操作人、操作时间、执行方法的全类名、执行方法名、方法运行时参数、返回值、方法执行时长
步骤:
准备工作:(可以私信找我要)
引入AOP的起步依赖
导入资料中准备好的数据库表结构,并引入对应的实体类
编码实现:
自定义注解@LogOperation

定义切面类,完成记录操作日志的逻辑

在需要记录的日志的Controller层的方法上,加上注解

重启服务
6.连接点
对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint类型
对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint的父类型
7.获取当前登录员工
员工登录成功后,哪里存储的有当前登录员工的信息:给客户端浏览器下发的jwt令牌中
如何从JWT令牌中获取当前登录用户的信息:获取请求头中传递的jwt令牌,并解析
TokenFilter 中已经解析了令牌的信息,如何传递给AOP程序、Controller、Service:ThreadLocal
ThreadLocal:
并不是一个Thread,而是Thread的局部变量
ThreadLocal为每个线程提供一份单独的存储空间,具有线程隔离的效果,不同的线程之间不会相互干扰

ThreadLocal常用方法:
public void set(T value)设置当前线程的线程局部变量的值
public T get()返回当前线程所对应的线程局部变量的值
public void remove()移除当前线程的线程局部变量
记录当前登录员工步骤:
定义ThreadLocal操作的工具类,用于操作当前登录员工ID

在TokenFilter中,解析完当前登录员工ID,将其存入ThreadLocal(用完之后需将其删除)


在AOP程序中,从ThreadLocal中获取当前登录员工的ID

hreadLocal的应用场景:
在同一个线程/同一个请求中,进行数据共享
更多推荐

所有评论(0)