当前位置: 首页 > news >正文

Spring学习04-[Spring容器核心技术AOP学习]

AOP学习

  • AOP介绍
  • 使用
    • 对业务方法添加计算时间的增强
  • @EnableAspectJAutoProxy
  • AOP的术语
  • 通知
    • 前置通知@Before
    • 后置通知@After
    • 返回通知@AfterReturning
    • 异常通知@AfterThrowing
    • 总结-通知执行顺序
  • 切点表达式的提取-使用@Pointcut进行抽取
  • 切点表达式的详细用法
    • execution和@annotation组合
  • SpringAOP和注解的使用-配置全局日志

AOP介绍

在这里插入图片描述
在这里插入图片描述

  • 如何在Spring中创建一个所谓切面?
    @Aspect+@Component+通知+切点
  • 切面里面的代码怎么运行在业务方法(之前、之后)?
    通知+切点

使用

实现一个对service方法的增强,添加日志

  • 添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>

在这里插入图片描述

对业务方法添加计算时间的增强

  • 业务类
@Service
public class UserService {public void add(){System.out.println("增加");}public void delete(){System.out.println("删除");}public void update(){System.out.println("修改");}public void query(){System.out.println("查询");}
}
  • 切面类
    啥叫面向切面编程:面向切面编程就是面向切面类进行编程
@Aspect //标记为切面类
@Component
public class LogAspect {//实现方法用时 切点表达式@Around("execution(* com.sping.service.UserService.*(..))")public Object log(ProceedingJoinPoint joinPoint) throws Throwable {//记录方法用时long startTime = System.currentTimeMillis();//执行具体的方法try {joinPoint.proceed(); //连接点就是具体的方法}catch (Exception e){System.out.println("方法执行异常");throw new Exception();}long endTime = System.currentTimeMillis();System.out.println("方法用时:" + (endTime - startTime) + "ms");return null;}}
  • 测试
  @Autowiredprivate UserService userService;@Testpublic void test() throws InterruptedException {userService.add();}

在这里插入图片描述

@EnableAspectJAutoProxy

在这里插入图片描述
在这里插入图片描述

AOP的术语

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
切面、切点、通知、连接点;顾问(通知+切点)
在这里插入图片描述

通知

  • 前置通知
  • 后置通知
  • 返回通知
  • 异常通知
    在定义切点的时候,可以把切点定义到另一个方法中,然后在通知中引入即可
@Aspect
@Component
public class LogAspect{@Pointcut("execution( * com.sping.service.UserService.*(..))")public void PointCut(){}@AfterReturning("PointCut()")public void log(){System.out.println("后置通知执行");}
}

环绕通知和其他通知的区别:环绕通知需要手动去拿到连接点执行目标方法,环绕方法更加的灵活

前置通知@Before

在目标方法执行之前执行

@Aspect
@Component
public class LogAspect{@Before("execution(* com.sping.service.*.*(..))")public void log(){System.out.println("前置通知执行");}
}

可以看到标注了前置通知后,前置通知的增强方法先执行,然后再执行目标方法
在这里插入图片描述

后置通知@After

与前置通知相反,后置通知是目标方法执行之后才会执行,通知里的增强方法

@Aspect
@Component
public class LogAspect{@After("execution(* com.sping.service.*.*(..))")public void log(){System.out.println("后置通知执行");}
}

在这里插入图片描述

返回通知@AfterReturning

执行位置:在方法执行完,返回值返回之前执行

    @Pointcut("execution( * com.sping.service.UserService.*(..))")public void PointCut(){}/*** 返回通知* 1、可以获取返回值* 2、在后置通知之前执行* 3、方法执行返回值需要手动声明*/@AfterReturning(value = "PointCut()",returning = "returnValue")public void log(){System.out.println("返回通知执行,返回值:" + returnValue);}

在这里插入图片描述

异常通知@AfterThrowing

   /*** 发生了异常后会执行*/@AfterThrowing(value = "PointCut()",throwing = "exception")public void log(Exception exception){System.out.println("异常通知执行" + exception.getMessage());}

在这里插入图片描述

总结-通知执行顺序

正常:前置通知---->目标方法---->返回通知---->后置通知(finallly)
异常:前置通知---->目标方法---->异常通知---->后置通知(finally)
在这里插入图片描述

切点表达式的提取-使用@Pointcut进行抽取

方便切点进行统一管理

  @Pointcut("execution( * com.sping.service.UserService.*(..))")public void PointCut(){}

切点表达式的详细用法

  • 切点标识符
  • execution:用于匹配方法执行连接点。这是使用SpringAOP时,使用的主要切点标识符,可以匹配到方法级别,细粒度
    在这里插入图片描述
  • @annotation:限制匹配连接点,在Spring AOP中执行的具有给定的注解(只有含有某些注解,才会生效)
    比如下面这段代码,只有我方法上加了@Log注解的才会被切到,进行增强
   @Pointcut("@annotation(com.sping.annotation.Log)")public void PointCut(){}

execution和@annotation组合

格式:@Pointcut(“execution()&&”+“@annotation()”)

  • 第一种方式:
     @Pointcut("execution(* com.sping.service.*.*(..))&&"+"@annotation(com.sping.annotation.Log)")public void PointCut() {}@Before(value = "PointCut()")public void log() {System.out.println("开始记录日志");}
  • 第二种方式:
    设置两个切点方法,再引入的时候通过&&符号进行引入
   @Pointcut("execution(* com.sping.service.*.*(..))")public void pointCutClass() {}@Pointcut("@annotation(com.sping.annotation.Log)")public void pointCutAnnotation(){}@Before(value = "pointCutClass()&&pointCutAnnotation()")public void log() {System.out.println("开始记录日志");}

SpringAOP和注解的使用-配置全局日志

  • 自定义注解
package com.test.aspect;import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {/*模块*/String title() default "";/*功能*/String action() default "";
}
  • 切面类
/*** @ClassName LogAspect* @Description* @Author 周志强* @Date 2021/5/12 12:27* @Version 1.0*/
@Aspect
@Component("logAspect")
public class LogAspect {private static Logger log= LoggerFactory.getLogger(LogAspect.class);//配置切入点@Pointcut("@annotation(com.test.aspect.Log)")public void logPointCut(){}//后置通知 用于拦截操作,在方法返回后执行@AfterReturning(pointcut = "logPointCut()")public void doBefore(JoinPoint joinPoint){handelLog(joinPoint,null);}//拦截异常操作,有异常时执行@AfterThrowing(value = "logPointCut()",throwing = "e")public void doAfter(JoinPoint joinPoint,Exception e){handelLog(joinPoint,e);}public void handelLog(JoinPoint joinpoint,Exception e){try {Log annotationLog = getAnnotationLog(joinPoint);if (annotationLog == null) {return;}String className = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();String action = annotationLog.action();String title = annotationLog.title();//打印日志,如有需要还可以存入数据库logger.info(">>>>>>>>>>>>>模块名称:{}",title);logger.info(">>>>>>>>>>>>>操作名称:{}",action);logger.info(">>>>>>>>>>>>>类名:{}",className);logger.info(">>>>>>>>>>>>>方法名:{}",methodName);}catch (Exception exception){logger.error("=前置通知异常=");logger.error("异常信息:{}",e.getMessage());e.printStackTrace();}}private static Log getAnnotationLog(JoinPoint joinPoint) throws Exception {Signature signature = joinPoint.getSignature();MethodSignature methodSignature= (MethodSignature) signature;Method method = methodSignature.getMethod();if (method != null) {return  method.getAnnotation(Log.class);}return null;}
}
http://www.lryc.cn/news/396090.html

相关文章:

  • 第5章-组合序列类型
  • 大话光学原理:2.最短时间原理、“魔法石”与彩虹
  • spring tx @Transactional 详解 `Advisor`、`Target`、`ProxyFactory
  • `CyclicBarrier` 是 Java 中的一个同步辅助工具类,它允许一组线程相互等待,直到所有线程都达到了某个公共屏障点(barrier point)
  • 华为机试HJ108求最小公倍数
  • Debezium报错处理系列之第114篇:No TableMapEventData has been found for table id:256.
  • 开发者必看:MySQL主从复制与Laravel读写分离的完美搭配
  • 二战架构师,拿下
  • 泛微开发修炼之旅--35关于基于页面扩展和自定义按钮实现与后端交互调用的方法
  • 原创作品—数据可视化大屏
  • AdaBoost集成学习算法理论解读以及公式为什么这么设计?
  • uniapp内置组件uni.navigateTo跳转后页面空白问题解决
  • 使用树莓派进行python开发,控制电机的参考资料
  • protobuf的使用
  • 笔记15:while语句编程练习
  • 打开excel时弹出stdole32.tlb
  • 349. 两个数组的交集
  • 重庆交通大学数学与统计学院携手泰迪智能科技共建的“智能工作室”
  • Pandas在生物信息学中的应用详解
  • ByteMD富文本编辑器的vue3配置
  • 基于antdesign封装一个react的上传组件
  • ARM裸机:一步步点亮LED(汇编)
  • 【单链表】05 有一个带头结点的单链表L,设计一个算法使其元素递增有序。
  • C语言入门基础题:奇偶 ASCII 值判断(C语言版)和ASCII码表,什么是ASCII码,它的特点和应用?
  • Numpy的广播机制(用于自动处理不同形状的数组)
  • 计算机图形学入门24:材质与外观
  • FTP、http 、tcp
  • 【虚幻引擎】UE4初学者系列教程开发进阶实战篇——生存游戏案例
  • 认识并理解webSocket
  • Scissor算法-从含有表型的bulkRNA数据中提取信息进而鉴别单细胞亚群