草庐IT

学习笔记——Spring中的AOP(AspectJ);Spring中AOP概述;Spring中AOP相关术语;AspectJ中切入点表达式;AspectJ中JoinPoint对象;AspectJ中通知

isDaHua 2023-04-16 原文

2023-01-18

一、Spring中的AOP

1、AspectJ

(1)简介

Java社区里最完整最流行的AOP框架

在Spring2.0以上版本中,可以使用AspectJ注解或基于XML配置的AOP

(2)使用AspectJ步骤

①在spring核心包的基础上添加支持jar包

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.10</version>
</dependency>

②创建spring的配置文件,配置自动扫描的包和AspectJ注解支持

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

<!--    开启组件扫描-->
    <context:component-scan base-package="com.hh"></context:component-scan>
<!--    开启AspectJ注解支持-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

③创建一个类作为切面,在类的上面添加注解

@Component:将当前类标识为一个组件

@Aspect:将当前类标识为切面类(非核心业务提取类)

@Component
@Aspect
public class MyLogging {

    /**
     * 方法之前
     */
    public static void beforeMethod(String methodName,Object[] arg){
        System.out.println("==>Calc中"+methodName+"方法(),参数:"+ Arrays.toString(arg));
    }
    /**
     * 方法之后
     */
    public static void afterMethod(String methodName,Object rs){
        System.out.println("==>Calc中"+methodName+"方法(),结果:"+rs);
    }
}

④将日志类中的方法添加“通知注解”

@Before

⑤测试

二、Spring中AOP概述

1、AOP:Aspect-Oriented Programming,面向切面编程(面向对象的一种补充)

优势:解决了代码分散与代码混乱的问题

2、OOP:Object-Oriented Programming,面向对象编程

三、Spring中AOP相关术语

1、横切关注点

非核心业务代码

2、切面(Aspect)

将横切关注点提取到类中,这个类称之为切面类

3、通知(Advice)

将横切关注点提取到类之后,横切关注点更名为通知

4、目标(Target)

目标对象,指的是需要被代理的对象(实现类CalcImpl)

5、代理(Proxy)

代理对象可以理解为中介

6、连接点(Joinpoint)

通知方法需要指定通知位置,这个位置称之为连接点(通知之前)

7、切入点(pointcut)

通知方法需要指定通知位置,这个位置称之为切入点(通知之后)

四、AspectJ中切入点表达式

1、语法:@Before(value="execution(权限修饰符 返回值类型 包名.类名.方法名(参数类型))")

2、通配符

(1)【*】

*:可以代表任意权限修饰符&返回值类型

*:可以代表任意包名、任意类名、任意方法名

(2)【..】

..  代表任意参数类型及参数个数

3、重用切入点表达式

(1)使用@PointCut注解,提取可重用的切入点表达式

 //重用切入点表达式
    @Pointcut("execution(* com.hh.aop.CalcImpl.*(..))")
    public void myPointCut(){}

(2)使用方法名()引入切入点表达式

@Before(value = "myPointCut()")
@After("myPointCut()")

五、AspectJ中JoinPoint对象

1、JoinPoint:切入点对象

2、作用:

(1)获取方法名称

String methodName = joinPoint.getSignature().getName();

注:joinPoint.getSignature()  表示方法签名(方法签名=方法名+参数列表)

(2)获取参数

Object[] args = joinPoint.getArgs();

六、AspectJ中通知

1、前置通知

(1)语法:@Before

(2)执行时机:指定方法之前执行

指定方法:即切入点表达式设置位置

注:如果目标方法中有异常,会执行

(3)示例代码

@Before(value = "myPointCut()")
    public void beforeMethod(JoinPoint joinPoint){
        //获取方法名称
        String methodName = joinPoint.getSignature().getName();
        //获取参数
        Object[] args = joinPoint.getArgs();
        System.out.println("【前置通知】==>Calc中"+methodName+"方法(),参数:"+ Arrays.toString(args));
    }

 

2、后置通知

(1)语法:@After

(2)执行时机:指定方法所有通知执行之后执行

注:如果目标方法中有异常,会执行

(3)示例代码

 @After("myPointCut()")
    public void afterMethod(JoinPoint joinPoint){
        //获取方法名称
        String methodName = joinPoint.getSignature().getName();
        //获取参数
        Object[] args = joinPoint.getArgs();
        System.out.println("【后置通知】==>Calc中"+methodName+"方法(),之后执行:"+ Arrays.toString(args));
    }

 

3、返回通知

(1)语法:@AfterReturnning

(2)执行时机:指定方法返回结果时执行

注:@AfterReturnning中returning属性中的的属性名与入参中参数名一致;

如果目标方法中有异常,不执行

(3)示例代码

@AfterReturning(value = "myPointCut()",returning = "rs")
    public void afterReturnning(JoinPoint joinPoint,Object rs){
        //获取方法名称
        String methodName = joinPoint.getSignature().getName();
        //获取参数
        Object[] args = joinPoint.getArgs();
        System.out.println("【返回通知】==>Calc中"+methodName+"方法(),返回结果执行!结果:"+ rs);
    }

4、异常通知

(1)语法:@AfterThrowing

(2)执行时机::指定方法出现异常时执行

注:@AfterThrowing中throwing属性中的的属性名与入参中参数名一致;

如果目标方法中有异常,执行

(3)示例代码

@AfterThrowing(value = "myPointCut()",throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint,Exception ex){
        //获取方法名称
        String methodName = joinPoint.getSignature().getName();
        //获取参数
        Object[] args = joinPoint.getArgs();
        System.out.println("【异常通知】==>Calc中"+methodName+"方法(),出现异常时执行!异常:"+ ex);
    }

说明:

①有异常:前置通知—>异常通知—>后置通知

②无异常:前置通知—>返回通知—>后置通知

5、环绕通知(前四个通知整合)

(1)语法:@Around

(2)作用:整合前四个通知

(3)注意:参数中必须使用ProceedingJoinPoint

(4)示例代码

 @Around(value = "myPointCut()")
    public Object aroundMethod(ProceedingJoinPoint pjp){

        //获取方法名称
        String methodName = pjp.getSignature().getName();
        //获取参数
        Object[] args = pjp.getArgs();
        //定义返回值
        Object rs = null;
        try {
            //前置通知 )
            System.out.println("【前置通知】==>Calc中"+methodName+"方法(),参数:"+ Arrays.toString(args));
            //触发目标对象的目标方法(加减乘除)
            rs = pjp.proceed();
            //返回通知(有异常不执行
            System.out.println("【返回通知】==>Calc中"+methodName+"方法(),返回结果执行!结果:"+ rs);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            //异常通知
            System.out.println("【异常通知】==>Calc中"+methodName+"方法(),出现异常时执行!异常:"+ throwable);
        }finally {
            //后置通知(有异常执行)
            System.out.println("【后置通知】==>Calc中"+methodName+"方法(),之后执行:"+ Arrays.toString(args));
        }
        return rs;
    }

 

有关学习笔记——Spring中的AOP(AspectJ);Spring中AOP概述;Spring中AOP相关术语;AspectJ中切入点表达式;AspectJ中JoinPoint对象;AspectJ中通知的更多相关文章

  1. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  2. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  3. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  4. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  5. 阿里云RDS——产品系列概述 - 2

    基础版云数据库RDS的产品系列包括基础版、高可用版、集群版、三节点企业版,本文介绍基础版实例的相关信息。RDS基础版实例也称为单机版实例,只有单个数据库节点,计算与存储分离,性价比超高。说明RDS基础版实例只有一个数据库节点,没有备节点作为热备份,因此当该节点意外宕机或者执行重启实例、变更配置、版本升级等任务时,会出现较长时间的不可用。如果业务对数据库的可用性要求较高,不建议使用基础版实例,可选择其他系列(如高可用版),部分基础版实例也支持升级为高可用版。基础版与高可用版的对比拓扑图如下所示。优势 性能由于不提供备节点,主节点不会因为实时的数据库复制而产生额外的性能开销,因此基础版的性能相对于

  6. spring.profiles.active和spring.profiles.include的使用及区别说明 - 2

    转自:spring.profiles.active和spring.profiles.include的使用及区别说明下文笔者讲述spring.profiles.active和spring.profiles.include的区别简介说明,如下所示我们都知道,在日常开发中,开发|测试|生产环境都拥有不同的配置信息如:jdbc地址、ip、端口等此时为了避免每次都修改全部信息,我们则可以采用以上的属性处理此类异常spring.profiles.active属性例:配置文件,可使用以下方式定义application-${profile}.properties开发环境配置文件:application-dev

  7. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

    我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

  8. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  9. python - python中有没有类似于ruby的||=的表达式 - 2

    我在Ruby中遇到了一个有趣的表达式:a||="new"表示如果没有定义a,则将"new"值赋给a;否则,a将保持原样。在进行一些数据库查询时很有用。如果设置了该值,我不想触发另一个数据库查询。所以我在Python中尝试了类似的思路:a=aifaisnotNoneelse"new"失败了。我认为这是因为如果未定义a,则无法在Python中执行“a=a”。所以我能得出的解决方案是检查locals()和globals(),或者使用try...except表达式:myVar=myVarif'myVar'inlocals()and'myVar'inglobals()else"new"或try:

  10. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

随机推荐