【JavaEE & Spring】Spring AOP

Spring AOP

  • [1. AOP概述](#1. AOP概述)
  • [2. Spring AOP快速⼊⻔](#2. Spring AOP快速⼊⻔)
    • [2.1 引⼊AOP依赖](#2.1 引⼊AOP依赖)
    • [2.2 编写AOP程序](#2.2 编写AOP程序)
  • [3. Spring AOP详解](#3. Spring AOP详解)
    • [3.1 SpringAOP核⼼概念](#3.1 SpringAOP核⼼概念)
      • [3.1.1 切点(Pointcut)](#3.1.1 切点(Pointcut))
      • [3.1.2 连接点(JoinPoint)](#3.1.2 连接点(JoinPoint))
      • [3.1.3 通知(Advice)](#3.1.3 通知(Advice))
      • [3.1.4 切⾯(Aspect)](#3.1.4 切⾯(Aspect))
    • [3.2 通知类型](#3.2 通知类型)
    • [3.3 @PointCut](#3.3 @PointCut)
    • [3.4 切⾯优先级@Order](#3.4 切⾯优先级@Order)
    • [3.5 切点表达式](#3.5 切点表达式)
      • [3.5.1 execution表达式](#3.5.1 execution表达式)
      • [3.5.2 @annotation](#3.5.2 @annotation)
        • [3.5.2.1 ⾃定义注解@MyAspect](#3.5.2.1 ⾃定义注解@MyAspect)
        • [3.5.2.2 切面类](#3.5.2.2 切面类)
        • [3.5.2.3 添加⾃定义注解](#3.5.2.3 添加⾃定义注解)
  • [4. Spring AOP原理](#4. Spring AOP原理)
    • [4.1 代理模式](#4.1 代理模式)
      • [4.1.1 静态代理](#4.1.1 静态代理)
      • [4.1.2 动态代理](#4.1.2 动态代理)

1. AOP概述

AOP是Spring框架的第⼆⼤核⼼(第⼀⼤核⼼是IoC)

  • 什么是 AOP?
    • AspectOrientedProgramming(⾯向切⾯编程)
    • 什么是⾯向切⾯编程呢?切⾯就是指某⼀类特定问题,所以AOP也可以理解为⾯向特定⽅法编程.
    • 简单来说: AOP是⼀种思想 ,是对某⼀类事情的集中处理
  • 什么是SpringAOP?
    • AOP是⼀种思想,它的实现⽅法有很多,有SpringAOP,也有AspectJ、CGLIB等.

AOP就可以做到在不改动这些原始⽅法的基础上,针对特定的⽅法进⾏功能的增强.

AOP的作⽤:在程序运⾏期间在不修改源代码的基础上对已有⽅法进⾏增强(⽆侵⼊性:解耦)

2. Spring AOP快速⼊⻔

学习什么是AOP后,我们先通过下⾯的程序体验下AOP的开发,并掌握Spring中AOP的开发步骤.

需求:统计图书系统各个接⼝⽅法的执⾏时间.

2.1 引⼊AOP依赖

在pom.xml⽂件中添加配置

xml 复制代码
<dependency>
	 <groupId>org.springframework.boot</groupId>
	 <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>

2.2 编写AOP程序

记录Controller中每个⽅法的执⾏时间

运⾏程序,观察⽇志

对程序进⾏简单的讲解:

  1. @Aspect:标识这是⼀个切⾯类
  2. @Around: 环绕通知,在⽬标⽅法的前后都会被执⾏.后⾯的表达式表⽰对哪些⽅法进⾏增强.
  3. ProceedingJoinPoint.proceed() 让原始⽅法执⾏

整个代码划分为三部分

我们通过AOP⼊⻔程序完成了业务接⼝执⾏耗时的统计.

通过上⾯的程序,我们也可以感受到AOP⾯向切⾯编程的⼀些优势:

  • 代码⽆侵⼊:不修改原始的业务⽅法,就可以对原始的业务⽅法进⾏了功能的增强或者是功能的改
  • 减少了重复代码
  • 提⾼开发效率
  • 维护⽅便

3. Spring AOP详解

下⾯我们再来详细学习AOP,主要是以下⼏部分

  • SpringAOP中涉及的核⼼概念
  • SpringAOP通知类型
  • 多个AOP程序的执⾏顺序

3.1 SpringAOP核⼼概念

3.1.1 切点(Pointcut)

切点(Pointcut), 也称之为"切⼊点"

Pointcut 的作⽤就是提供⼀组规则(使⽤AspectJpointcutexpressionlanguage来描述),告诉程序对哪些⽅法来进⾏功能增强.

3.1.2 连接点(JoinPoint)

满⾜切点表达式规则的⽅法,就是连接点.也就是可以被AOP控制的⽅法

以⼊⻔程序举例,所有

com.example.demo.controller

路径下的⽅法,都是连接点.

上述BookController中的⽅法都是连接点

切点和连接点的关系

连接点是满⾜切点表达式的元素.切点可以看做是保存了众多连接点的⼀个集合.

3.1.3 通知(Advice)

通知就是具体要做的⼯作,指哪些重复的逻辑,也就是共性功能(最终体现为⼀个⽅法)

⽐如上述程序中记录业务⽅法的耗时时间,就是通知.

在AOP⾯向切⾯编程当中,我们把这部分重复的代码逻辑抽取出来单独定义,这部分代码就是通知的内容.

3.1.4 切⾯(Aspect)

切⾯(Aspect)=切点(Pointcut)+通知(Advice)

通过切⾯就能够描述当前AOP程序需要针对于哪些⽅法,在什么时候执⾏什么样的操作.

切⾯既包含了通知逻辑的定义,也包括了连接点的定义.

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

3.2 通知类型

上⾯我们讲了什么是通知, 接下来学习通知的类型.

@Around 就是其中⼀种通知类型,表⽰环绕通知. Spring中AOP的通知类型有以下⼏种:

  • @Around:环绕通知,此注解标注的通知⽅法在⽬标⽅法前,后都被执⾏
  • @Before:前置通知,此注解标注的通知⽅法在⽬标⽅法前被执⾏
  • @After:后置通知,此注解标注的通知⽅法在⽬标⽅法后被执⾏,⽆论是否有异常都会执⾏
  • @AfterReturning: 返回后通知,此注解标注的通知⽅法在⽬标⽅法后被执⾏,有异常不会执⾏
  • @AfterThrowing:异常后通知,此注解标注的通知⽅法发⽣异常后执⾏
  1. 正常运⾏的情况

程序正常运⾏的情况下, @AfterThrowing

标识的通知⽅法不会执⾏从上图也可以看出来,

@Around 标识的通知⽅法包含两部分,⼀个"前置逻辑",⼀个"后置逻辑".其中"前置逻辑"会先于@Before 标识的通知⽅法执⾏,"后置逻辑"会晚于@After 标识的通知⽅法执⾏

  1. 异常时的情况

注意事项:

  • @Around 环绕通知需要调⽤ ProceedingJoinPoint.proceed() 来让原始⽅法执⾏,其他通知不需要考虑⽬标⽅法执⾏.
  • @Around 环绕通知⽅法的返回值,必须指定为Object,来接收原始⽅法的返回值,否则原始⽅法执⾏完毕,是获取不到返回值的.
  • ⼀个切⾯类可以有多个切点.

3.3 @PointCut

上述代码就可以修改为:

当切点定义使⽤private修饰时,仅能在当前切⾯类中使⽤,当其他切⾯类也要使⽤当前切点定义时,就需要把private改为public.引⽤⽅式为:全限定类名.⽅法名()

3.4 切⾯优先级@Order

当我们在⼀个项⽬中,定义了多个切⾯类时,并且这些切⾯类的多个切⼊点都匹配到了同⼀个⽬标⽅法.当⽬标⽅法运⾏的时候,这些切⾯类中的通知⽅法都会执⾏,那么这⼏个通知⽅法的执⾏顺序是什么样的呢?

Spring 给我们提供了⼀个新的注解,来控制这些切⾯通知的执⾏顺序:@Order


3.5 切点表达式

上⾯的代码中,我们⼀直在使⽤切点表达式来描述切点.下⾯我们来介绍⼀下切点表达式的语法.

切点表达式常⻅有两种表达⽅式

  1. execution(...):根据⽅法的签名来匹配
  2. @annotation() :根据注解匹配

3.5.1 execution表达式

execution() 是最常⽤的切点表达式,⽤来匹配⽅法,语法为:

其中:访问修饰符和异常可以省略

3.5.2 @annotation

实现步骤:

  1. 编写⾃定义注解
  2. 使⽤@annotation 表达式来描述切点
  3. 在连接点的⽅法上添加⾃定义注解
3.5.2.1 ⾃定义注解@MyAspect

创建⼀个注解类(和创建Class⽂件⼀样的流程,选择Annotation就可以了)




3.5.2.2 切面类

使⽤@annotation 切点表达式定义切点,只对@MyAspect ⽣效

切⾯类代码如下:

3.5.2.3 添加⾃定义注解

Spring AOP 的实现方式

4. Spring AOP原理

上⾯我们主要学习了SpringAOP的应⽤,接下来我们来学习SpringAOP的原理,也就是Spring是如何实现AOP的.

Spring AOP是基于动态代理来实现AOP的,咱们学习内容主要分以下两部分

  1. 代理模式
  2. Spring AOP源码剖析

4.1 代理模式

代理模式,也叫委托模式.

定义:为其他对象提供⼀种代理以控制对这个对象的访问.它的作⽤就是通过提供⼀个代理类,让我们在调⽤⽬标⽅法的时候,不再是直接对⽬标⽅法进⾏调⽤,⽽是通过代理类间接调⽤.

在某些情况下,⼀个对象不适合或者不能直接引⽤另⼀个对象,⽽代理对象可以在客⼾端和⽬标对象之间起到中介的作⽤.

使⽤代理前:

使⽤代理后:


代理模式的主要⻆⾊

  1. Subject: 业务接⼝类.可以是抽象类或者接⼝(不⼀定有)
  2. RealSubject: 业务实现类. 具体的业务执⾏,也就是被代理对象.
  3. Proxy: 代理类.RealSubject的代理.

⽐如房屋租赁

Subject 就是提前定义了房东做的事情,交给中介代理,也是中介要做的事情

RealSubject: 房东

Proxy: 中介

UML类图如下:

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进⾏⼀些功能的附加与增强.

根据代理的创建时期,代理模式分为静态代理和动态代理.

  • 静态代理:由程序员创建代理类或特定⼯具⾃动⽣成源代码再对其编译,在程序运⾏前代理类的.class ⽂件就已经存在了.
  • 动态代理:在程序运⾏时,运⽤反射机制动态创建⽽成.

4.1.1 静态代理

静态代理:在程序运⾏前,代理类的.class⽂件就已经存在了.



上⾯这个代理实现⽅式就是静态代理(仿佛啥也没⼲).

从上述程序可以看出,虽然静态代理也完成了对⽬标对象的代理,但是由于代码都写死了,对⽬标对象的每个⽅法的增强都是⼿动完成的,⾮常不灵活. 所以⽇常开发⼏乎看不到静态代理的场景

4.1.2 动态代理

相⽐于静态代理来说,动态代理更加灵活.

我们不需要针对每个⽬标对象都单独创建⼀个代理对象,⽽是把这个创建代理对象的⼯作推迟到程序运⾏时由JVM来实现.也就是说动态代理在程序运⾏时,根据需要动态创建⽣成.

⽐如房屋中介,我不需要提前预测都有哪些业务,⽽是业务来了我再根据情况创建.

Java也对动态代理进⾏了实现,并给我们提供了⼀些API,常⻅的实现⽅式有两种:

  1. JDK动态代理
  2. CGLIB动态代理

动态代理在我们⽇常开发中使⽤的相对较少,但是在框架中⼏乎是必⽤的⼀⻔技术.学会了动态代理之后,对于我们理解和学习各种框架的原理也⾮常有帮助.

JDK动态代理

JDK动态代理类实现步骤

  1. 定义⼀个接⼝及其实现类(静态代理中的HouseSubject 和RealHouseSubject )
  2. ⾃定义InvocationHandler 并重写 invoke⽅法在invoke ⽅法中我们会调⽤⽬标⽅法(被代理类的⽅法)并⾃定义⼀些处理逻辑
  3. 通过Proxy.newProxyInstance(ClassLoader loader,Class<?>\[\]
    interfaces,InvocationHandler h) ⽅法创建代理对象



CGLIB动态代理



Spring 默认使用的代理方法如下

相关推荐
xcl09256 小时前
北京24小时自助健身房系统软件开发实战:从架构到部署全流程指南
java·spring boot·架构
一 乐7 小时前
动漫书销售商城|基于springboot + vue动漫书销售商城(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕业设计
卓怡学长8 小时前
w214基于jsp知道特产网
java·intellij-idea
步行cgn8 小时前
Spring 注解使用详解
java·spring
一条小小yu8 小时前
Spring IoC的理解
java·后端·spring
落魄实习生8 小时前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
旺仔学长 哈哈9 小时前
springboot钓鱼爱好者交流平台APP设计与实现
java·spring boot·mysql·充电桩管理系统
自强的小白10 小时前
核心功能(Service接口)
java·mybatis
乌暮11 小时前
深入理解 Java 泛型:把「万能盒子」用对、用稳
java·开发语言·后端·学习