面向注解编程—Spring 注解看这一篇就够了(2)

news2024/11/29 8:39:47

面向注解编程—Spring注解大全(AOP篇)

AOP英文全称:Aspect Oriented Programming(面向切面编程、面向方面编程),其实说白 了,面向切面编程就是面向特定方法编程。

AOP的作用:在程序运行期间在不修改源代码的基础上对已有方法进行增强(无侵入性: 解耦)

AOP的常见的应用场景 如下:

  • 记录系统的操作日志
  • 权限控制
  • 事务管理:我们前面所讲解的Spring事务管理,底层其实也是通过AOP来实现的,只要添加 @Transactional注解之后,AOP程序自动会在原始方法运行前先来开启事务,在原始方法运行完 毕之后提交或回滚事务

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AOP快速入门

@Aspect

@Component
@Aspect //当前类为切面类
@Slf4j
public class TimeAspect {
    @Around("execution(* com.itheima.service.*.*(..))")
    public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
        //记录方法执行开始时间
        long begin = System.currentTimeMillis();
        
        //执行原始方法
        Object result = pjp.proceed();
        
        //记录方法执行结束时间
        long end = System.currentTimeMillis();
        
        //计算方法执行耗时
        log.info(pjp.getSignature()+"执行耗时: {}毫秒",end-begin);
        
        return result;
    }
}

该类实现了统计各个业务层方法执行耗时

AOP核心概念

连接点:JoinPoint

连接点指的是可以被aop控制的方法。例如:入门程序当中所有的业务方法都是可以被aop控制的方法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通知:Advice

指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

切入点:PointCut

匹配连接点的条件,通知仅会在切入点方法执行时被应用

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

切面:Aspect

描述通知与切入点的对应关系(通知+切入点)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

切面所在的类,我们一般称为切面类(被@Aspect注解标识的类)

通知类型

  • @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
  • @Before:前置通知,此注解标注的通知方法在目标方法前被执行
  • @After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
  • @AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执 行
  • @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行

在入门程序当中,已经展示了一种功能最为强大的通知类型:Around环绕通知

//前置通知
@Before("execution(* com.itheima.service.*.*(..))")

//环绕通知
@Around("execution(* com.itheima.service.*.*(..))")

//后置通知
@After("execution(* com.itheima.service.*.*(..))")

//返回后通知(程序在正常执行的情况下,会执行的后置通知)
@AfterReturning("execution(* com.itheima.service.*.*(..))")

//异常通知(程序在出现异常的情况下,执行的后置通知)
@AfterThrowing("execution(* com.itheima.service.*.*(..))")

@PointCut:解决这个切入点表达式重复的问题

@Slf4j
@Component
@Aspect
public class MyAspect1 {
    //切入点方法(公共的切入点表达式)
    @Pointcut("execution(* com.itheima.service.*.*(..))")
    private void pt(){
    
    }
    
    //前置通知(引用切入点)
    @Before("pt()")
        public void before(JoinPoint joinPoint){
        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(JoinPoint joinPoint){
        log.info("after ...");
    }
    
    //返回后通知(程序在正常执行的情况下,会执行的后置通知)
    @AfterReturning("pt()")
        public void afterReturning(JoinPoint joinPoint){
        log.info("afterReturning ...");
    }
    
    //异常通知(程序在出现异常的情况下,执行的后置通知)
    @AfterThrowing("pt()")
        public void afterThrowing(JoinPoint joinPoint){
        log.info("afterThrowing ...");
    }
}

@Order():使用@Order注解,控制通知的执行顺序:

@Slf4j
@Component
@Aspect
@Order(2) //切面类的执行顺序(前置通知:数字越小先执行; 后置通知:数字越小
越后执行)
public class MyAspect2 {
    //前置通知
    @Before("execution(* com.itheima.service.*.*(..))")
    public void before(){
    	log.info("MyAspect2 -> before ...");
     }
    
    //后置通知
    @After("execution(* com.itheima.service.*.*(..))")
    public void after(){
        log.info("MyAspect2 -> after ...");
    }
}
@Slf4j
@Component
@Aspect
@Order(3) //切面类的执行顺序(前置通知:数字越小先执行; 后置通知:数字越小越后执行)
public class MyAspect3 {
    //前置通知
    @Before("execution(* com.itheima.service.*.*(..))")
    public void before(){
    log.info("MyAspect3 -> before ...");
 	}
    
	//后置通知
	@After("execution(* com.itheima.service.*.*(..))")
    public void after(){
    log.info("MyAspect3 -> after ...");
 	}
}

切入点表达式

execution

格式 execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)

@Before("execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")
  • *****:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数, 也可以通配包、类、方法名的一部分
  • :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
@annotation

自定义注解:MyLog

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {

}

业务类:DeptServiceImpl

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;
    
    @Override
    @MyLog //自定义注解(表示:当前方法属于目标方法)
    public List<Dept> list() {
        List<Dept> deptList = deptMapper.list();
        //模拟异常
        //int num = 10/0;
        return deptList;
     }
     
    @Override
    @MyLog //自定义注解(表示:当前方法属于目标方法)
    public void delete(Integer id) {
        //1. 删除部门
        deptMapper.delete(id);
     }
     
    @Override
    public void save(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.save(dept);
     }
     
    @Override
    public Dept getById(Integer id) {
    	return deptMapper.getById(id);
     }
     
    @Override
    public void update(Dept dept) {
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.update(dept);
     }
}

切面类

@Slf4j
@Component
@Aspect
public class MyAspect6 {
    //针对list方法、delete方法进行前置通知和后置通知
    
    //前置通知
    @Before("@annotation(com.itheima.anno.MyLog)")
    public void before(){
    	log.info("MyAspect6 -> before ...");
    }
    
    //后置通知
    @After("@annotation(com.itheima.anno.MyLog)")
    public void after(){
    	log.info("MyAspect6 -> after ...");
     }
}
  • execution切入点表达式 根据我们所指定的方法的描述信息来匹配切入点方法,这种方式也是最为常用的一种方式 如果我们要匹配的切入点方法的方法名不规则,或者有一些比较特殊的需求,通过 execution切入点表达式描述比较繁琐
  • @annotation 切入点表达式 基于注解的方式来匹配切入点方法。 这种方式虽然多一步操作,我们需要自定义一个注解,但是相对来比较灵活。我们需要匹配哪个方法,就在方法上加上对应的注解就可以了

连接点

在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法 名、方法参数等。

  • 对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint类型
  • 对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint的父类型

示例代码:

@Slf4j
@Component
@Aspect
public class MyAspect7 {
    @Pointcut("@annotation(com.itheima.anno.MyLog)")
    private void pt(){}
    
    //前置通知
    @Before("pt()")
    public void before(JoinPoint joinPoint){
        log.info(joinPoint.getSignature().getName() + " MyAspect7 ->
        before ...");
     }
                 
    //后置通知
    @Before("pt()")
    public void after(JoinPoint joinPoint){
        log.info(joinPoint.getSignature().getName() + " MyAspect7 -> after ...");
     }
                 
    //环绕通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //获取目标类名
        String name = pjp.getTarget().getClass().getName();
        log.info("目标类名:{}",name);
        
        //目标方法名
        String methodName = pjp.getSignature().getName();
        log.info("目标方法名:{}",methodName);
        
        //获取方法执行时需要的参数
            Object[] args = pjp.getArgs();
        log.info("目标方法参数:{}", Arrays.toString(args));
        
        //执行原始方法
        Object returnValue = pjp.proceed();
        return returnValue;
     }
}



     //目标方法名
        String methodName = pjp.getSignature().getName();
        log.info("目标方法名:{}",methodName);
        
        //获取方法执行时需要的参数
            Object[] args = pjp.getArgs();
        log.info("目标方法参数:{}", Arrays.toString(args));
        
        //执行原始方法
        Object returnValue = pjp.proceed();
        return returnValue;
     }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1286264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【好书推荐】Flutter入门经典

目录 作者简介内容简介文章详解介绍《Flutter入门经典》读者对象《Flutter入门经典》内容要点《Flutter入门经典》内容结构第I部分&#xff1a;Flutter编程基础第II部分&#xff1a;充当媒介的Flutter&#xff1a;具象化一个应用第III部分&#xff1a;创建可用于生产环境的应用…

广州数字孪生赋能工业制造,加速推进制造业数字化转型

广州数字孪生赋能工业制造&#xff0c;加速推进制造业数字化转型。数字孪生系统基于历史数据、实时数据&#xff0c;采用人工智能、大数据分析等新一代信息技术对物理实体的组成、特征、功能和性能进行数字化定义和建模。通过构建在信息世界对物理实体的等价映射&#xff0c;对…

Geodesic in Heat: 一种测地线计算方法

在之前的博客中&#xff0c;我已经介绍过了使用Fast Marching算法计算测地线。Fast Marching的好处是实现简单&#xff0c;方便扩展在点云上。但是缺点是精度不够&#xff0c;求解不平滑。早在2013年&#xff0c;Crane et al. [1]就已经提出利用热流来估算测地距离。我很早就知…

深入理解Java核心技术:Java工程师的实用干货笔记

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在Java工程师的职业生涯中&#xff0c;深入理解…

使用C语言创建高性能网络爬虫IP池

目录 一、引言 二、IP池的设计 1、需求分析 2、架构设计 3、关键技术 三、IP池的实现 1、存储实现 2、调度实现 3、通信实现 4、异常处理实现 四、代码示例 五、性能优化 六、测试与分析 七、结论 一、引言 随着互联网的快速发展&#xff0c;网络爬虫成为了获取…

日志JavaAgent-NoClassDefFoundError

一、引言 组内最近做了一个日志公共组件&#xff0c;用的是javaagent的方式&#xff0c;之前搞的maven jar包每次都要把所有系统都发一遍&#xff0c;太麻烦。 javaagent通过Java虚拟机&#xff08;JVM&#xff09;的Instrumentation API来实现代码的侵入。通过Instrumentation…

matlab diff和gradient

gradient 求解梯度。 示例 FX gradient(F) 返回向量 F 的一维数值梯度。输出 FX 对应于 ∂F/∂x&#xff0c;即 x&#xff08;水平&#xff09;方向上的差分。点之间的间距假定为 1。 使用方法&#xff1a; x -2:0.2:2; y x’; z x .* exp(-x.^2 - y.^2); [px,py] gradien…

K8S部署nginx并且使用NFS存储数据

安装NFS 在master安装NFS systemctl start nfs-server修改配置 /etc/exports /data *(rw,no_root_squash,no_all_squash,sync)目录为 /data 允许所有地址访问 验证下 [rootmaster nginx]# showmount -e 192.168.57.61 Export list for 192.168.57.61: /data *共享可以正常…

1.uniapp基础

1.uniapp基础 官方文档&#xff1a;uni-app官网 1.1开发工具 &#xff08;1&#xff09;工具&#xff1a; HBuilderX HBuilderX-高效极客技巧 1.2 新建项目 &#xff08;1&#xff09; 文件》新建项目 ​ &#xff08;2&#xff09;选择相应的配置信息&#xff0c;填写项目根路…

python超详细基础文件操作【建议收藏】

文章目录 前言1 文件操作1.1 文件打开与关闭1.1.1 打开文件1.1.2 关闭文件 1.2 访问模式及说明 2 文件读写2.1 写数据&#xff08;write&#xff09;2.2 读数据&#xff08;read&#xff09;2.3 读数据&#xff08;readlines&#xff09;2.3 读数据&#xff08;readline&#x…

数据结构 / 队列 / 循环队列 / 概念

1. 定义 为充分利用向量空间&#xff0c;克服假溢出现象的方法是&#xff1a;将向量空间想象为一个首尾相接的圆环&#xff0c;并称这种向量为循环向量。存储在其中的队列称为循环队列&#xff08;Circular Queue&#xff09;。循环队列是把顺序队列首尾相连&#xff0c;把存储…

正式发布! 加速科技ST2500A飙速赶来!

在新场景、新应用海量增长的驱动下&#xff0c;芯片测试需求也在日益多元化和快速扩展。加速科技始终致力于以客户的实际需求为导向&#xff0c;基于领先的半导体测试技术为千行百业提供全场景的测试解决方案&#xff0c;推出新一代ST2500A数模混合信号测试机。 ST2500A是基于…

(六)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)

一、无人机模型简介&#xff1a; 单个无人机三维路径规划问题及其建模_IT猿手的博客-CSDN博客 参考文献&#xff1a; [1]胡观凯,钟建华,李永正,黎万洪.基于IPSO-GA算法的无人机三维路径规划[J].现代电子技术,2023,46(07):115-120 二、Tiki-taka算法&#xff08;TTA&#xf…

Linux-Linux安装JDK及配置环境 及 遇到的问题

下载linux环境对应的JDK的tar.gz包 配置JDK环境&#xff1a;编辑 sudo vim /etc/profile 在文件的最下方&#xff0c;填写 export JAVA_HOME/usr/local/src/software/jdk1.8 export CLASSPATH.:$JAVA_HOME/lib/tools.jar export PATH$JAVA_HOME/bin:$PATH 执行生效命令&…

UVM实现component之间transaction级别的通信

my_model是从i_agt中得到my_transaction&#xff0c;并把 my_transaction传递给my_scoreboard。在UVM中&#xff0c;通常使用TLM&#xff08;Transaction Level Modeling&#xff09;实现component之间transaction级别 的通信。 在UVM的transaction级别的通信 中&#xff0c;数…

Git介绍与安装使用

目录 1.Git初识 1.1提出问题 1.2如何解决--版本控制器 1.3注意事项 2.Git安装 2.1Linux-centos安装 2.2Linux-ubuntu安装 2.3Windows安装 3.Git基本操作 3.1创建Git本地仓库 3.2配置Git 4.认识⼯作区、暂存区、版本库 1.Git初识 1.1提出问题 不知道你工作或学习时…

Spring AOP解析

基本概念 之前写过如何实现方法增强&#xff0c;见链接&#xff1a;一篇文章了解如何实现方法增强&#xff0c;实现原理即采用的是AOP&#xff0c;那么本篇文章就主要是为了了解Spring AOP的实现。 面向切面编程&#xff08;Aspect Oriented Programming&#xff09; 在软件…

Apollo新版Beta技术沙龙,震撼来袭!

在2023年12月2日&#xff0c;我有幸参加百度Apollo举行的技术交流活动&#xff0c;Apollo是一个百度公司开发的开源的自动驾驶项目&#xff0c;这次线下技术交流让我对自动驾驶有了深入的了解。 在活动中&#xff0c;来自Apollo项目的专家们对 Apollo 技术的进行介绍和演示。他…

ValueError: not enough values to unpack (expected 3, got 2)

我在使用cv2.findContours函数中遇到以上错误&#xff0c;经查询找到该错误原因&#xff1a; 在 OpenCV 4.X 中&#xff0c;函数 cv2.findContours()仅有两个返回值&#xff0c; 其语法格式为&#xff1a; contours, hierarchy cv2.findContours( image, mode, method) 若不…

2023版本idea插件开发踩坑记录(一)

在进行idea开发的时候&#xff0c;开始仿照着写第一个插件hello world的时候&#xff0c;运行的时候一直运行不成功。参考了很多博客都是如此 后面对官方文档读了一遍&#xff0c;就发现其中的原委&#xff0c;这个的话估计会有很多人跟我一样踩坑 具体原因是&#xff0c;idea插…