SpringBootWeb AOP
事务管理
rollbackFor属性
propagation属性
案例
AOP
基础
进阶
通知类型
通知顺序
切入点表达式
execution
@annotation
连接点
案例
实体类
接口方法
切面类
事务管理
rollbackFor属性
propagation属性
REQUIRED:大部分情况下都是用该传播行为即可。
REOUIRES_NEW:当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。
案例
Grep Console插件可用于日志过滤筛选
AOP
基础
进阶
通知类型
@Slf4j
@Component
@Aspect
public class MyAspect1 {@Pointcut("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")public void pt() {}@Before("pt()")public void before() {log.info("before ...");}@Around("pt()")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {log.info("around before ...");//调用目标对象的原始方法执行Object result = proceedingJoinPoint.proceed();log.info("around after ...");return result;}@After("pt()")public void after() {log.info("after ...");}@AfterReturning("pt()")public void afterReturning() {log.info("afterReturning ...");}@AfterThrowing("pt()")public void afterThrowing() {log.info("afterThrowing ...");}
}
通知顺序
切入点表达式
execution
//切面类
@Slf4j
@Aspect
@Component
public class MyAspect6 {//@Pointcut("execution(public void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")//@Pointcut("execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")//@Pointcut("execution(void delete(java.lang.Integer))") //包名.类名不建议省略//@Pointcut("execution(void com.itheima.service.DeptService.delete(java.lang.Integer))")//@Pointcut("execution(void com.itheima.service.DeptService.*(java.lang.Integer))")//@Pointcut("execution(* com.*.service.DeptService.*(*))")//@Pointcut("execution(* com.itheima.service.*Service.delete*(*))")//@Pointcut("execution(* com.itheima.service.DeptService.*(..))")//@Pointcut("execution(* com..DeptService.*(..))")//@Pointcut("execution(* com..*.*(..))")//@Pointcut("execution(* *(..))") //慎用@Pointcut("execution(* com.itheima.service.DeptService.list()) || " +"execution(* com.itheima.service.DeptService.delete(java.lang.Integer))")private void pt(){}@Before("pt()")public void before(){log.info("MyAspect6 ... before ...");}}
@annotation
@annotation 切入点表达式,用于匹配标识有特定注解的方法。
连接点
在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
对于 @Around 通知,获取连接点信息只能使用 ProceedingJoinPoint
对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint 的父类型
//切面类
@Slf4j
@Aspect
@Component
public class MyAspect8 {@Pointcut("execution(* com.itheima.service.DeptService.*(..))")private void pt(){}@Before("pt()")public void before(JoinPoint joinPoint){log.info("MyAspect8 ... before ...");}@Around("pt()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {log.info("MyAspect8 around before ...");//1. 获取 目标对象的类名 .String className = joinPoint.getTarget().getClass().getName();log.info("目标对象的类名:{}", className);//2. 获取 目标方法的方法名 .String methodName = joinPoint.getSignature().getName();log.info("目标方法的方法名: {}",methodName);//3. 获取 目标方法运行时传入的参数 .Object[] args = joinPoint.getArgs();log.info("目标方法运行时传入的参数: {}", Arrays.toString(args));//4. 放行 目标方法执行 .Object result = joinPoint.proceed();//5. 获取 目标方法运行的返回值 .log.info("目标方法运行的返回值: {}",result);log.info("MyAspect8 around after ...");return result;}
}
案例
步骤
准备:
在案例工程中引入AOP的起步依赖
导入资料中准备好的数据库表结构,并引入对应的实体类
编码:
自定义注解 @Log
定义切面类,完成记录操作日志的逻辑
获取当前登录用户
获取request对象,从请求头中获取到jwt令牌,解析令牌获取出当前用户的id。
实体类
接口方法
切面类
@Slf4j
@Aspect
@Component
public class LogAspect {@Autowiredprivate OperateLogMapper operateLogMapper;@Autowiredprivate HttpServletRequest request;@Around("@annotation(com.itheima.anno.Log)")public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {String jwt = request.getHeader("token");Claims claims = JwtUtils.parseJWT(jwt);Integer operateUser = (Integer)claims.get("id");LocalDateTime operateTime= LocalDateTime.now();String className = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();String methodParams = Arrays.toString(args);long begin = System.currentTimeMillis();Object result=joinPoint.proceed();long end = System.currentTimeMillis();String returnValue = JSONObject.toJSONString(result);Long costTime = end - begin;OperateLog oprateLog= new OperateLog(null,operateUser,operateTime,className,methodName,methodParams,returnValue,costTime);operateLogMapper.insert(oprateLog);log.info("aop记录日志成功{}",oprateLog);return result;}
}