3 - AOP

news2024/11/20 6:16:22

1. 快速入门

1.1 基本说明

AOP(aspect oriented programming) ,面向切面编程

切面类中声明通知方法:

  • 前置通知:@Before
  • 返回通知:@AfterReturning
  • 异常通知:@AfterThrowing
  • 后置通知:@After
  • 环绕通知:@Around

1.2 快速入门 

参考视频:B站 三更草堂视频

1.3 细节说明

1)切面类方法命名

  • showBeginLog()
  • showSuccessEndLog()
  • showExceptionLog()
  • showFinallyEndLog()

2)切入表达式更多的配置

使用模糊配置

@Before(value="execution(* com.hspedu.aop.proxy.SmartDog.*(..))")

这个就表示这个切面方法作用与  com.hspedu.aop.proxy.SmartDog 类的函数

3)所有访问权限

@Before(value="execution(* *.*(..))")
  1. 第一个 * 表示 任意方法权限及任意返回值
  2. 第二个 * 表示 任意路径
  3. 第三个 * 表示 任意方法
  4. (..) 表示任意数量,任意类型的参数

所有包的下所有有类的所方法,都会被执行该前置通知方法

4)使用基于注解的AOP需要在配置文件里开启

<aop:aspectj-autoproxy/> 

5)开启了基于注解的后获取对象

这个时候去获取 ioc 容器里的对象的话,在底层被转换为 代理对象

我们获取注入的对象, 也可以通过 id 来获取, 但是也要转成接口类型


2. AOP-切入表达式

2.1 具体使用

1)作用

通过表达式的方式来定位一个或多个具体的切入点

2)语法细节

格式: execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名] ([参数列表]))

若目标类、接口 与切面类在同一个包下,可以省略包名

2.2 注意事项和细节

1)表达式指向类

切入表达式也可以指向类的方法, 这时切入表达式会对该类/对象生效

2)表达式指向接口

切入表达式也可以指向接口的方法, 这时切入表达式会对实现了接口的类/对象生效

3)表达式指向没有实现接口的类

切入表达式也可以对没有实现接口的类,进行切入

@Component
class Car {
    public void run() {
        System.out.println("car run");
    }
}

切面类:

@Before(value = "execution(public void com.hspedu.spring.aop.aspectj.Car.run())")
    public static void showBeginLog3(JoinPoint joinPoint) {
        //获取方法签名
        Signature signature = joinPoint.getSignature();
        System.out.println("方法执行前--方法名--" + signature.getName());
    }

测试:

@Test
    public void carTestProxy() {
        //得到spring容器
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans08.xml");
        Car car = ioc.getBean(Car.class);
        System.out.println(car.getClass());
        car.run();

    }

不一样的时,这此取出来的 car 对象的运行类型:

    class com.hspedu.spring.aop.aspectj.Car$$EnhancerBySpringCGLIB$$8e9f1fa7

这个时候 就是 Spring 的 CGlib 方案:取出的时 Car 对象的子类

参考:jdk的Proxy与spring的CGlib


3. 切入方法细节

3.1 AOP-JoinPoint 

常用方法一览

  • joinPoint.getSignature().getName(); 获取目标方法名
  • joinPoint.getSignature().getDeclaringType().getSimpleName(); 获取目标方法所属类的简单类名
  • joinPoint.getSignature().getDeclaringTypeName();  获取目标方法所属类的类名
  • joinPoint.getSignature().getModifiers(); /获取目标方法声明类型(public、private、protected)
  • Object[] args = joinPoint.getArgs();  获取传入目标方法的参数,返回一个数组
  • joinPoint.getTarget();   获取被代理的对象
  • joinPoint.getThis();    获取代理对象自己

3.2 返回通知获知结果

如何在返回通知方法获取返回结果?

**
* returning = "res", Object res 名称保持一致
* @param joinPoint
* @param res 调用 getSum() 返回的结果
*/
@AfterReturning(value="execution(public float com.hspedu.spring.aop.joinpoint.SmartDog.getSum(float, float))",returning = "res")
public void showSuccessEndLog(JoinPoint joinPoint, Object res) {
    System.out.println("返回通知" + "--结果是--" + res );
}

3.3 AOP-异常通知中获取异常

@AfterThrowing(value="execution(public float
com.hspedu.spring.aop.joinpoint.SmartDog.getSum(float, float))",throwing = "throwable")
public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {
    System.out.println("异常通知 -- 异常信息--" + throwable);
}

3.4 环绕通知(了解)

环绕通知可以完成其它四个通知要做的事情

@Aspect //表示这个类是一个切面类
@Component //需要加入到 IOC 容器
public class SmartAnimalAspect {
    //=====环绕通知 start=====
    //@Around(value = "execution(* *.*(..))")
    @Around(value="execution(public float
    com.hspedu.spring.aop.joinpoint.SmartDog.getSum(float, float))")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        Object result = null;
        String methodName = joinPoint.getSignature().getName();
        try {
            //1.相当于前置通知完成的事情
            Object[] args = joinPoint.getArgs();
            List<Object> argList = Arrays.asList(args);
            System.out.println("AOP 环绕通知--" + methodName + "开始了--参数有:
                " + argList);
            //在环绕通知中一定要调用 joinPoint.proceed()来执行目标方法
            result = joinPoint.proceed();
            //2.相当于返回通知完成的事情
            System.out.println("AOP 环绕通知" + methodName + "结束了--结果是:"
                + result);
        } catch (Throwable throwable) {
            //3.相当于异常通知完成的事情
            System.out.println("AOP 环绕通知" + methodName + "抛异常--异常对象:" + 
                throwable);
        } finally {
            //4.相当于最终通知完成的事情
            System.out.println("AOP 后置通知" + methodName + "最终结束...");
        }
    return result;
}

环绕通知和动态代理完成的事情相似

3.5  切入点表达式重用

为了统一管理切入点表达式,可以使用切入点表达式重用技术

在切面类上添加:

//=====AOP-切入点表达式重用 start ======
/*
* 这样定义的一个切入点表达式,就可以在其它地方直接使用
*/
@Pointcut(value="execution(public float
com.hspedu.spring.aop.joinpoint.SmartDog.getSum(float, float))")
public void myPointCut() {
}

这样其他切面方法就可以简写:

@Before(value = "myPointCut()")
public void showBeginLog(JoinPoint joinPoint) { //前置方法
    Signature signature = joinPoint.getSignature();
    //得到方法名.
    String method_name = signature.getName();
    //得到参数
    Object[] args = joinPoint.getArgs();
    System.out.println("前置通知" + "--调用的方法是 " + method_name + "--参数是
        --" + Arrays.asList(args));
}

3.6 AOP-切面优先级问题

如果同一个方法,有多个切面在同一个切入点切入,那么执行的优先级如何控制?

@order(value=n) 

通过设定 order 的value 值来控制, n 值越小,优先级越高

@Aspect //表示这个类是一个切面类
@Order(value = 2)
@Component //需要加入 IOC 容器
public class SmartAnimalAspect2 {
    /**
     内部是切面方法
    */
}

/****************************/

@Aspect //表示这个类是一个切面类
@Order(value = 1)
@Component //需要加入 IOC 容器
public class SmartAnimalAspect {
    /**
     内部是切面方法
    */
}

输出的信息顺序,类似 Filter 的过滤链式调用机制


3.  基于 XML 配置 AOP

前面是通过注解来配置 aop 的,在 spring 中,我们也可以通过 xml 的方式来配置 AOP

1)准备对象

去掉切面方法的所有注解

2)配置 xml

<!-- 配置 SmartAnimalAspect bean -->
<bean id="smartAnimalAspect" class="com.hspedu.spring.aop.xml.SmartAnimalAspect"/>

<!--配置 SmartDog-->
<bean class="com.hspedu.spring.aop.xml.SmartDog" id="smartDog"/>

<aop:config>
    <!-- 配置统一切入点 -->
    <aop:pointcut expression="execution(public float
        com.hspedu.spring.aop.xml.SmartDog.getSum(float, float))" id="myPointCut"/>
    <aop:aspect ref="smartAnimalAspect" order="1">
    <!-- 配置各个通知对应的切入点 -->
        <aop:before method="showBeginLog" pointcut-ref="myPointCut"/>
        <aop:after-returning method="showSuccessEndLog" pointcut-ref="myPointCut" 
            returning="res"/>
        <aop:after-throwing method="showExceptionLog" pointcut-ref="myPointCut" 
            throwing="throwable"/>
        <aop:after method="showFinallyEndLog" pointcut-ref="myPointCut"/>
        <!-- 还可以配置环绕通知 -->
        <!-- <aop:around method=""/> -->
    </aop:aspect>
</aop:config>

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

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

相关文章

并发List源码剖析

并发包中的并发List只有CopyOnWriteArrayList。 CopyOnWriteArrayList是一个线程安全的ArrayList,对其进行的修改操作都是在底层的一个复制的数组(快照)上进行的&#xff0c;也就是使用了写时复制策略。 在CopyOnWriteArrayList的类图中&#xff0c;每个CopyOnWriteArrayList对…

(学习日记)2024.01.05:一份关于自行车定位的调研

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

电流检测方法

电路检测电路常用于&#xff1a;高压短路保护、电机控制、DC/DC换流器、系统功耗管理、二次电池的电流管理、蓄电池管理等电流检测等场景。 对于大部分应用&#xff0c;都是通过感测电阻两端的压降测量电流。 一般使用电流通过时的压降为数十mV&#xff5e;数百mV的电阻值&…

BLDC 电机和 PMSM 的结构区别

BLDC 电机和 PMSM 的结构类似&#xff0c;其永磁体均置于转子&#xff0c;并被定义为同步电机。在同步电机中&#xff0c;转子与定子磁场同步&#xff0c;即转子的旋转速度与定子磁场相同。它们的主要区别在于其反电动势&#xff08;反 EMF&#xff09;的形状。电机在旋转时充当…

NPS配置https访问web管理页面

因为NPS默认也支持http的访问&#xff0c;所以在部署完后就一直没在意这个事情。 因为服务器是暴露在公网内的&#xff0c;所以还是要安全一点才行。不然一旦远控的机器被破解了就很危险了 一、使用nginx反向代理访问 1、首先在nps的配置文件里关闭使用https选项&#xff0c;…

midjourney教程【--niji 5】

博客底部扫码加微信&#xff0c;免费领mj Niji Model Version 5还可以使用不同的美学使用--style选项&#xff0c;以实现独特的外观。试试 --style cute, --style scenic, --style original , or --style expressive mj&#xff0c;a boy sitting on the ground looking soci…

Logstash:迁移数据到 Elasticsearch

在生产环境中&#xff0c;不使用 Apache Kafka 等流平台进行数据迁移并不是一个好的做法。 在这篇文章中&#xff0c;我们将详细探讨 Apache Kafka 和 Logstash 的关系。 但首先让我们简单了解一下 Apache Kafka 的含义。 Apache Kafka 是分布式流平台&#xff0c;擅长实时数据…

计算机找不到vcomp140.dll怎样修复?马上教会你修复dll问题

在计算机系统运行过程中&#xff0c;遭遇“vcomp140.dll丢失”的场景并不少见&#xff0c;这一问题的出现往往伴随着软件无法正常启动、运行时错误提示或者系统性能下降等现象。具体场景可能包括但不限于&#xff1a;用户在尝试打开某个依赖于Visual C Redistributable库的应用…

有趣的事,讲给有趣的人听

哈哈哈&#xff0c;今天不写技术了&#xff0c;今天分享一下生活&#xff0c;技术我们什么时候都可以学&#xff0c;但是生活更值得我们现在就去更好的体验&#xff01; 两年多的涤生大数据&#xff0c;认识了形形色色的小伙伴&#xff0c;陆续沟通下来6000多人&#xff0c;彼时…

代码随想录算法训练营第三十二天|122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II

题目&#xff1a;122.买卖股票的最佳时机II 文章链接&#xff1a;代码随想录 视频链接&#xff1a;LeetCode:122.买卖股票的最佳时机|| 题目链接&#xff1a;力扣题目链接 图释&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {// 查看…

【笔记】书生·浦语大模型实战营——第四课(XTuner 大模型单卡低成本微调实战)

【参考&#xff1a;tutorial/xtuner/README.md at main InternLM/tutorial】 【参考&#xff1a;(4)XTuner 大模型单卡低成本微调实战_哔哩哔哩_bilibili-【OpenMMLab】】 总结 学到了 linux系统中 tmux 的使用 了解了 XTuner 大模型微调框架的使用 pth格式参数转Hugging …

如何挖掘过期老域名并注册一个 DA 为 10 的高价值老域名

原文来源&#xff1a;https://guomuyu.com/registered-a-high-value-domain.html 最近有一些有意从事外贸的朋友阅读了《2024最新外贸建站&#xff1a;WordPress自建外贸独立站教程》这篇文章。然而&#xff0c;当他们尝试注册与自己所从事行业相关的域名时&#xff0c;却发现…

LeetCode114二叉树展开为链表(相关话题:后序遍历)

题目描述 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同。 示例…

系统性学习vue-vue核心

做了三年前端,但很多系统性的知识没有学习 还是从头系统学习一遍吧 课程是b站的Vue2.0Vue3.0课程 后续还会学习的如下,就重新开一篇了,不然太长,之后放链接 vue组件化编程 vue-cli 脚手架 vue中的ajax vue-router vuex element-ui vue3 老师推荐的vscode针对vue的插件: Vue 3…

ssh协议以及操作流程

ssh协议 1.是一种安全通道协议 2.对通信数据进行了加密处理&#xff0c;用于远程管理 3.对数据进行压缩 在日常生活中&#xff0c;我们使用的是openssh openssh 服务名称&#xff1a;sshd 服务端主程序&#xff1a;/usr/sbin/sshd 服务端配置文件&#xff1a;/etc/ssh/sshd_con…

计算机找不到msvcp120.dll如何解决?总结五个可靠的教程

在计算机使用过程中&#xff0c;遇到“找不到msvcp120.dll”这一问题常常令人困扰。msvcp120.dll作为Windows系统中至关重要的动态链接库文件&#xff0c;对于许多应用程序的正常运行起着不可或缺的作用。那么&#xff0c;究竟是什么原因导致找不到msvcp120.dll呢&#xff1f;又…

odoo17 | 模型之间的交互

前言 在前一章中&#xff0c;我们使用继承来修改模块的行为。在我们的房地产场景中&#xff0c;我们希望更进一步&#xff0c;能够为我们的客户生成发票。Odoo提供了一个发票&#xff08;Invoicing&#xff09;模块&#xff0c;所以直接从我们的房地产模块创建一个发票会很简洁…

笔记:flutter中一些流行的 UI 相关库推荐(不断更新)

笔记&#xff1a;flutter中一些流行的 UI 相关库&#xff08;不断更新&#xff09; CSDN&#xff1a;https://jclee95.blog.csdn.net本文收录了很多在 flutter pub 上显示流行度较高的第三方UI库和UI框架&#xff0c;对它们的效果进行了截图&#xff0c;目的是方便开发时进行查…

如何利用小程序介绍公司品牌形象?

企业小程序的建设对于现代企业来说已经成为了一项必不可少的工作。随着移动互联网的快速发展&#xff0c;越来越多的职场人士和创业老板希望通过小程序来提升企业形象&#xff0c;增强与用户的互动&#xff0c;实现更好的商业效果。在这个过程中&#xff0c;使用第三方制作平台…

录第第五十八天——每日温度,下一个更大元素|

单调栈 栈里的元素保持单调递增或者递减&#xff0c;栈内元素是元素下标。单调栈的本质是空间换时间&#xff0c;因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素&#xff0c;优点是整个数组只需要遍历一次求一个元素右边第一个更大元素&#xff0c;单调栈…