首页 > 其他分享 >Spring----AOP入门介绍、原理与使用

Spring----AOP入门介绍、原理与使用

时间:2023-06-16 10:47:11浏览次数:39  
标签:匹配 Spring 切入点 System ---- void AOP 方法 public

AOP

介绍

  • AOP:面向切面编程,无入侵式编程一种编程范式,指导开发者如何组织程序结构
    • OOP:面向对象
  • 作用:在不惊动原始设计的基础上为其做功能增强

概念定义

  • Aspect(切面):描述通知与切入点的对应关系(执行位置和共性之间的关系)
    • Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
  • Joint point(连接点):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
    • 表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。
    • 在SpringAOP中,理解为方法的执行
  • Pointcut(切入点):匹配连接点的式子
    • 表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
    • 在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
  • Advice(增强 / 通知):在切入点处执行的操作,也就是共性功能
    • Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
    • 通知写入通知类中
    • 在SpringAOP中,功能最终以方法的形式呈现
  • Target(目标对象):织入 Advice 的目标对象.。
  • Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

入门案例

例1:在接口执行前输出当前系统时间

  1. 导入坐标(pom.xml)

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    
  2. 制作连接点方法(原始操作,Dao接口与实现类)

    @Component("UserService")
    @Repository
    public class UserServiceImpl {
        public void save(){
            System.out.println(System.currentTimeMillis());
            System.out.println("service save");
        }
        public void update(){
            System.out.println("service update");
        }
    }
    
  3. 制作共性功能

    public class MyAdvice {
        public void method() {
            System.out.println(System.currentTimeMillis());//共性功能
        }
    }
    
  4. 定义切入点

    //class MyAdvice
    //@Pointcut("execution()"")括号内表示这个方法为切入点
    @Pointcut("execution(void spring.configTest.UserServiceImpl.update())")
    private void pt(){
    }
    
  5. 绑定切入点与增强的关系

    //class MyAdvice
    //@Before()表示当发现切入点时,在切入点执行之前使用增强
    @Before("pt()")
    public void method() {
        System.out.println(System.currentTimeMillis());
    }
    
  6. 让Spring识别AOP

    1. 在通知类前加入@Component@Aspect

      @Component
      @Aspect
      public class MyAdvice {
          ...
      }
      
    2. 在配置类前加入@EnableAspectJAutoProxy

      @Configuration
      @ComponentScan(basePackages = "spring.configTest")
      @EnableAspectJAutoProxy
      public class SpringConfig {
          ...
      }
      
  • 运行结果:userService.save()userService.update() 一致

AOP工作流程&核心概念

  • 工作流程

    1. Spring容器启动

    2. 读取所有切面配置中的切入点

    3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点

      • 匹配失败,创建对象

      • 匹配成功,创建原始对象(目标对象)的代理对象

    4. 获取bean执行方法

      • 获取bean,调用方法并执行,完成操作

      • 获取的ben是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

  • 核心概念

    • 目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的

    • 代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

  • SpringAOP的本质:代理模式

AOP切入点表达式

  • 切入点:要进行增强的方法

  • 切入点表达式:要进行增强的方法的描述方法

  • 通知的类型

    • @Before:切入点方法运行前运行
    • @After:切入点方法运行后运行
    • @Around:前后都运行
      • 环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
      • 通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
      • 对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型
      • 原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
      • 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象
    • @AfterReturning:正常执行完毕后运行
    • @AfterThrowing:抛出异常后运行
  • 切入点表达式标准格式

    execution (public User com.UserService.findById(int))
    
    1. 动作关键字:描述切入点的行为动作,例如execution:表示执行到指定切入点
    2. 访问修饰符:public,private等,可以省略
    3. 返回值:使用 * 匹配任意类型
    4. 目标类/接口(需要完整包名):省略时匹配任意类型, .. 匹配包及其子包的所有类,*
    5. 方法名:使用 * 表示通配符以匹配任意方法, xxx* 匹配名称以 xxx 开头的方法
    6. 参数:可以匹配多个,(..) 匹配有任意数量参数的方法,括号内 * 表示任意类型属性
    7. 异常名:方法定义中抛出指定异常,省略时匹配任意类型
  • 类型匹配语法

    • +:匹配任何数量字符;
    • ..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
    • +:匹配指定类型的子类型**;仅能作为后缀放在类型模式后边。
  • 示例

    • java.lang.String 匹配String类型;
    • java.*.String 匹配java包下的任何“一级子包”下的String类型;
    • 如匹配java.lang.String,但不匹配java.lang.ss.String
    • java..* 匹配java包及任何子包下的任何类型;
    • java.lang.*ing 匹配任何java.lang包下的以ing结尾的类型;
    • java.lang.Number+ 匹配java.lang包下的任何Number的子类型;

获取通知数据

  • 获取切入点方法的参数

    • JoinPoint:适用于前置、后置、返回后、抛出异常后通知

    • ProceedJointPoint:适用于环绕通知

      //public class UserImpl
      public String test2(int id, String pwd) {
          System.out.println("test2");
          return id+pwd;
      }
      
      //public class MyAdvice
      @Pointcut("execution(* spring.configTest.UserImpl.test2(..))")
      private void pt(){}
      
      @Around("pt()")
      public Object around(ProceedingJoinPoint pjp) throws Throwable{
          Object[] args = pjp.getArgs();
          System.out.println("around");
          System.out.println(Arrays.toString(args));
          return pjp.proceed(args);
      }
      
      @After("pt()")
      public void after(JoinPoint jp) throws Throwable{
          Object[] args = jp.getArgs();
          System.out.println("after");
          System.out.println(Arrays.toString(args));
      }
      
      >>around
      >>[10, 22]
      >>test2
      >>after
      >>[10, 22]
      >>update
      
  • 获取切入点方法返回值

    • 返回后通知

    • 环绕通知

    • 例(test2函数与上文一致)

      //public class MyAdvice
      //returning = 的意思是,如果此函数有返回值,则将返回值填入ret中
      @Pointcut("execution(* spring.configTest.UserImpl.test2(..))")
      private void pt(){
      }
      
      @AfterReturning(value = "pt()",returning = "ret")
      public void afterReturning(Object ret){
          System.out.println(ret);
      }
      
      >>test2
      >>1022
      
  • 获取切入点方法运行异常信息(了解即可)

    • 抛出异常后通知
    • 环绕通知

标签:匹配,Spring,切入点,System,----,void,AOP,方法,public
From: https://www.cnblogs.com/WgBlogSpace/p/17484969.html

相关文章

  • Go-map、切片、数组循环常见问题总结
    map1、forrangemap在开始执行循环的时候,底层做了随机种子,故其循环是随机的。packagemainimport"fmt"funcmain(){ a:=map[int]int{0:1,1:2,2:3,3:4,4:5} for_,c:=rangea{ fmt.Println(c) }}输出:34512多次执行,结果不同数组packagema......
  • Verilog语法 - 阻塞赋值 & 非阻塞赋值
    参考https://zhuanlan.zhihu.com/p/720344011.非阻塞赋值代码如下always@(posedgeclk)beginb<=a;c<=b;endRTL会综合出两个寄存器串行,如下波形图所示,第一个时钟上升沿来临时,会把a的旧值赋值给b;同时,c获得的是b的旧值,而不是从a那里拿到的新值。非阻......
  • Spring事务基础介绍
    事务本文只介绍声明式事务管理,即使用AOP实现,使用@Transactional开始事务事务角色事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法接口介绍PlatformTransactionManager:Spring事务......
  • linux服务器mysql的简单安装和使用(基于二进制文件方式)
    mysql下载地址https://downloads.mysql.com/archives/community/版本选择 直接放置/root目录下     常规操作查找以前是否装有mysqlrpm-qa|grep-imysql如果找到或者以前安装过有遗留文件,操作如下命令删除命令:rpm-e--nodeps包名删除老版本m......
  • 如何为程序添加ICON
    如何为程序添加ICON程序图标位于窗口的左上角,也位于任务栏中。JavaFX可以使用一张png图片来设置图标。效果展示示例代码importjavafx.application.Application;importjavafx.scene.Scene;importjavafx.scene.image.Image;importjavafx.scene.layout.StackPane;im......
  • BT139-800E-ASEMI代理恩智浦双向可控硅BT139-800E
    编辑:llBT139-800E-ASEMI代理恩智浦双向可控硅BT139-800E型号:BT139-800E品牌:NXP/恩智浦封装:TO-220BT139-800E产品特性:电压性能最高可达800伏平面钝化电压的坚固性和可靠性60Hz半周期内,浪涌性能高达140A在所有四个象限触发BT139-800E描述:BT139-800E系列双向可控硅采用标准TO......
  • 什么是SEO
    SEO是搜索引擎优化的缩写,它是一种通过优化网站和网页,以提高其在搜索引擎中的排名和可见性的技术和实践。搜索引擎是人们在互联网上查找信息的主要工具,常见的搜索引擎包括Google、Bing和小度等。当用户在搜索引擎中输入关键词或短语时,搜索引擎会根据其算法和规则,显示与这些关键词......
  • 深入理解nil
    nil是Go中熟悉且重要的预先声明的标识符。它是多种类型零值的字面表示。许多具有其他一些流行语言经验的新Go程序员可能会将其nil视为null(或NULL)其他语言的对应物。这部分是正确的,但nil 在Go和null(或NULL)其他语言之间存在许多差异。按照Go语言规范,任何类型在未初始化时都对应一......
  • SpringMVC基础详解(包含示例)
    SpringMVC简介SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,跟Spring,Mybatis框架并称为SSM。是由Spring官方提供的基于MVC设计理念的web框架也是基于Servlet封装的用于实现MVC控制的框架,实现前端和服务端的交互与Servlet技术功能相同,均是......
  • AtCoder Beginner Contest 251 G Intersection of Polygons
    洛谷传送门AtCoder传送门经典结论,一个点\(P(x,y)\)在一个凸多边形内部\(S=\{(x_i,y_i)\}\)的充要条件是\(\foralli\in[1,n],(x_{i+1}-x_i,y_{i+1}-y_i)\times(x-x_i,y-y_i)\ge0\),其中\(S\)的点按照逆时针排列。然后我们运用叉积的一个性质......