Spring AOP
一、基本理论、原理
1、AOP是什么?
答:AOP(Aspect Oriented Programming: 面向切面编程)可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术
AOP的编程思想就是把很多类对象中的横切问题点,从业务逻辑中分离出来,从而打到解耦的目的,增加代码的重用性,提高发开效率。
2、使用场景
- 日志记录、
- 异常处理
- 权限验证
- 缓存处理
- 事务处理
- 数据持久化
- 效率检查
- 内容分发
- 等
二、注解
1. Aspect 概念
- aspect:切面,切面由切点和通知组成,即包括横切逻辑的定义也包括连接点的定义
- pointcut: 切点,每个类都拥有多个连接点,可以理解是连接点的集合
- joinpoint:连接点,程序执行的某个特定位置,如某个方法调用前后等
- weaving:织入,将增强添加到目录类的具体连接点的过程
- advice:通知,是织入到目标类连接点上的一段代码,就是增强到什么地方,增强什么内容
- target:目标对象,通知织入到目标类
- aop Proxy:代理对象,即增强后产生的对象
2. 通知的种类
- Before advice
- 前置通知,即在目标方法调用执行前执行。注意:既无论方法是否遇到异常都执行
- After returning advice
- 后置通知,在目标方法执行后通知,前提是目标方法没有遇到异常,如果有异常则不执行
- After throwing advice
- 异常通知,在目标方法抛出异常时执行,可以获取异常信息
- After finally advice
- 最终通知,在目标方法执行后执行,无论是否是异常都执行
- Around advice
- 环绕通知,最强大的通知类型,可以控制目标方法的执行,(通过调用ProceedingJoinPoint.proceed()),可以在目标执行全过程中进行执行
3.Spring AOP底层实现
是通过JDK动态代理或CGLib代理在运行时期在对象初始化阶段织入代码的。
<aside>
💡 JDK动态代理与CGLib代理的区别
- JDK动态代理基于接口实现
- CGLib代理基于类的继承实现 </aside>
三、实操
基于注解的判断用户登录
- 注解方法:
@**interface** CheckLogin
package cn.zhenghe.info.service.util.checkLogin; /** * @Description 登录校验注解 * @author liudi * @date 2022/05/09 * @Version 1.0 */ public @interface CheckLogin { }
- aspect方法:
CheckLoginAspect
package cn.zhenghe.info.service.util.checkLogin; import cn.zhenghe.framework.core.utils.message.Message; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; /** * @Description 登录校验切面 * @author liudi * @date 2022/05/09 * @Version 1.0 */ @Aspect @Component @Slf4j public class CheckLoginAspect { /** * 只要加了@CheckLogin的方法都会走到这里 * @param point * @return */ @Around("@annotation(cn.zhenghe.info.service.util.checkLogin.CheckLogin)") public Object checkLogin(ProceedingJoinPoint point) { try { // 从header中获取token RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes; HttpServletRequest request = attributes.getRequest(); String xUseridHeader = request.getHeader("x-userid-header"); if (StringUtils.isBlank(xUseridHeader)) { return Message.exception("未登录"); } // 执行后续的方法 return point.proceed(); } catch (Throwable e) { return Message.exception("未登录"); } } }
- 使用: 只需要在需要验证登录的方法上使用注解:
@CheckLogin
,就可以判断是否登录