Spring AOP 的概念及其作用

这篇具有很好参考价值的文章主要介绍了Spring AOP 的概念及其作用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、什么是 Spring AOP?

在介绍 Spring AOP 之前,首先要了解一下什么是 AOP
AOP Aspect Oriented Programming ):面向切面编程,它是一种思想, 它是对某一类事情的集中处 。比如用户登录权限的效验,没学 AOP 之前,我们所有需要判断用户登录的页面(中的方法),都要各自实现或调用用户验证的方法,然而有了 AOP 之后,我们只需要在某一处配置一下,所有需要判断用户登录页面(中的方法)就全部可以实现用户登录验证了,不再需要每个方法中都写相同的用户登录验证了。
AOP 是一种思想,而 Spring AOP 是一个框架,提供了一种对 AOP 思想的实现,它们的关系和 IoC与 DI 类似。

二、为什要用 AOP?

想象一个场景,我们在做后台系统时,除了登录和注册等几个功能不需要做用户登录验证之外,其他几乎所有页面调用的前端控制器( Controller )都需要先验证用户登录的状态,那这个时候我们要怎么处 理呢?
我们之前的处理方式是每个 Controller 都要写一遍用户登录验证,然而当你的功能越来越多,那么你要写的登录验证也越来越多,而这些方法又是相同的,这么多的方法就会代码修改和维护的成本。那有没有简单的处理方案呢?答案是有的,对于这种功能统一,且使用的地方较多的功能,就可以考虑 AOP 来统一处理了
除了统一的用户登录判断之外, AOP 还可以实现:
  • 统一日志记录
  • 统一方法执行时间统计
  • 统一的返回格式设置
  • 统一的异常处理
  • 事务的开启和提交等
也就是说 使用 AOP 可以扩充多个对象的某个能力 ,所以 AOP 可以说是 OOP Object Oriented
Programming ,面向对象编程)的补充和完善。

三、Spring AOP 应该怎么学习呢?

Spring AOP 学习主要分为以下 3 个部分:
1. 学习 AOP 是如何组成的?也就是学习 AOP 组成的相关概念。
2. 学习 Spring AOP 使用。
3. 学习 Spring AOP 实现原理。
下面我们分别来看。

3.1 AOP 组成

3.1.1 切面(Aspect

切面( Aspect )由切点( Pointcut )和通知( Advice )组成,它既包含了横切逻辑的定义,也包括了连接点的定义。
切面是包含了:通知、切点和切面的类,相当于 AOP 实现的某个功能的集合。

3.1.2 连接点(Join Point

应用执行过程中能够插入切面的一个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
连接点相当于需要被增强的某个 AOP 功能的所有方法。

3.1.3 切点(Pointcut

Pointcut 是匹配 Join Point 的谓词。
Pointcut 的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述)来匹配 Join Point,给满足规则的 Join Point 添加 Advice
切点相当于保存了众多连接点的一个集合(如果把切点看成一个表,而连接点就是表中一条一条的
数据)。

3.1.4 通知(Advice

切面也是有目标的 —— 它必须完成的工作。在 AOP 术语中, 切面的工作被称之为通知
通知:定义了切面是什么,何时使用,其描述了切面要完成的工作,还解决何时执行这个工作的问题。
Spring 切面类中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件后会通知本方法进行调用:
  • 前置通知使用 @Before:通知方法会在目标方法调用之前执行。
  • 后置通知使用 @After:通知方法会在目标方法返回或者抛出异常后调用。
  • 返回之后通知使用 @AfterReturning:通知方法会在目标方法返回后调用。
  • 抛异常后通知使用 @AfterThrowing:通知方法会在目标方法抛出异常后调用。
  • 环绕通知使用 @Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。
切点相当于要增强的方法。
AOP 整个组成部分的概念如下图所示,以多个页面都要访问用户登录权限为例:
Spring AOP 的概念及其作用,spring,java,后端,aop

3.2 Spring AOP 实现

接下来我们使用 Spring AOP 来实现一下 AOP 的功能,完成的目标是拦截所有 UserController 里面的方法,每次调用 UserController 中任意一个方法时,都执行相应的通知事件。
Spring AOP 的实现步骤如下:
1. 添加 Spring AOP 框架支持。
2. 定义切面和切点。
3. 定义通知。

3.2.1 添加 AOP 框架支持

pom.xml 中添加如下配置:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-bootstarter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

3.2.2 定义切面和切点

切点指的是具体要处理的某一类问题,比如用户登录权限验证就是一个具体的问题,记录所有方法的执行日志就是一个具体的问题,切点定义的是某一类问题。
Spring AOP 切点的定义如下,在切点中我们要定义拦截的规则,具体实现如下:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect // 表明此类为一个切面
@Component
public class UserAspect {
// 定义切点,这里使用 AspectJ 表达式语法
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut(){ }
}
其中 pointcut 方法为空方法,它不需要有方法体,此方法名就是起到一个 标识 的作用,标识下面的通知方法具体指的是哪个切点(因为切点可能有很多个)。
切点表达式说明
AspectJ 支持三种通配符:
  • * :匹配任意字符,只匹配一个元素(包,类,或方法,方法参数)。
  • * .. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使用。
  • + :表示按照类型匹配指定类的所有类,必须跟在类名后面,如 com.cad.Car+ ,表示继承该类的所有子类包括本身。
切点表达式由切点函数组成,其中 execution() 是最常用的切点函数,用来匹配方法,语法为:
execution(< 修饰符 >< 返回类型 >< . . 方法 ( 参数 )>< 异常 >)
修饰符 异常 可以省略。
 
表达式示例
Spring AOP 的概念及其作用,spring,java,后端,aop

 

3.2.3 定义相关通知

通知定义的是被拦截的方法具体要执行的业务,比如用户登录权限验证方法就是具体要执行的业务。
Spring AOP 中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件后会通知本方法进行调用:
  • 前置通知使用@Before:通知方法会在目标方法调用之前执行。
  • 后置通知使用@After:通知方法会在目标方法返回或者抛出异常后调用。
  • 返回之后通知使用@AfterReturning:通知方法会在目标方法返回后调用。
  • 抛异常后通知使用@AfterThrowing:通知方法会在目标方法抛出异常后调用。
  • 环绕通知使用@Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自
  • 定义的行为。
具体实现如下:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class UserAspect {
// 定义切点方法
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut(){ }
// 前置通知
@Before("pointcut()")
public void doBefore(){
System.out.println("执行 Before 方法");
}
// 后置通知
@After("pointcut()")
public void doAfter(){
System.out.println("执行 After 方法");
}
// return 之前通知
@AfterReturning("pointcut()")
public void doAfterReturning(){
System.out.println("执行 AfterReturning 方法");
}
// 抛出异常之前通知
@AfterThrowing("pointcut()")
public void doAfterThrowing(){
System.out.println("执行 doAfterThrowing 方法");
}
// 添加环绕通知
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint){
Object obj = null;
System.out.println("Around 方法开始执行");
try {
// 执行拦截方法
obj = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("Around 方法结束执行");
return obj;
}
}
经过以上的代码我们就能实现 Spring AOP 了。

3.3 Spring AOP 实现原理

Spring AOP 是构建在 动态代理 基础上,因此 Spring AOP 的支持局限于方法级别的拦截
Spring AOP 支持 JDK Proxy CGLIB 方式实现动态代理。默认情况下,实现了接口的类,使用 AOP 会基于 JDK 生成代理类,没有实现接口的类,会基于 CGLIB 生成代理类。
Spring AOP 的概念及其作用,spring,java,后端,aop

织入(Weaving):代理的生成时机

织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:
  • 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
  • 类加载器:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader,可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-time weaving. LTW)就支持以这种方式织入切面。
  • 运行期:切面在应用运行的某一时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象。SpringAOP就是以这种方式织入切面的。

动态代理

此种实现在设计模式上称为动态代理模式,在实现的技术手段上,都是在 class 代码运行期,动态的织 入字节码。

我们学习 Spring 框架中的AOP,主要基于两种方式:JDK CGLIB 的方式。这两种方式的代理目标都是被代理类中的方法,在运行期,动态的织入字节码生成代理类。

  • CGLIBJava中的动态代理框架,主要作用就是根据目标类和方法,动态生成代理类。
  • Java中的动态代理框架,几乎都是依赖字节码框架(如 ASMJavassist 等)实现的。
  • 字节码框架是直接操作 class 字节码的框架。可以加载已有的class字节码文件信息,修改部分信息,或动态生成一个 class
JDK 动态代理实现
JDK 实现时,先通过实现 InvocationHandler 接口创建方法调用处理器,再通过 Proxy 来创建代理类。
以下为代码实现:
import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理:使用JDK提供的api(InvocationHandler、Proxy实现),此种方式实现,要求被代理类必
须实现接口
public class PayServiceJDKInvocationHandler implements InvocationHandler {
//目标对象即就是被代理对象
private Object target;
public PayServiceJDKInvocationHandler( Object target) {
this.target = target;
}
//proxy代理对象
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
//1.安全检查
System.out.println("安全检查");
//2.记录日志
System.out.println("记录日志");
//3.时间统计开始
System.out.println("记录开始时间");
//通过反射调用被代理类的方法
Object retVal = method.invoke(target, args);
//4.时间统计结束
System.out.println("记录结束时间");
return retVal;
}
public static void main(String[] args) {
PayService target= new AliPayService();
//方法调用处理器
InvocationHandler handler =
new PayServiceJDKInvocationHandler(target);
//创建一个代理类:通过被代理类、被代理实现的接口、方法调用处理器来创建
PayService proxy = (PayService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class[]{PayService.class},
handler
);
proxy.pay();
}
}
CGLIB 动态代理实现
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;
import java.lang.reflect.Method;
public class PayServiceCGLIBInterceptor implements MethodInterceptor {
//被代理对象
private Object target;
public PayServiceCGLIBInterceptor(Object target){
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy
methodProxy) throws Throwable {
//1.安全检查
System.out.println("安全检查");
//2.记录日志
System.out.println("记录日志");
//3.时间统计开始
System.out.println("记录开始时间");
//通过cglib的代理方法调用
Object retVal = methodProxy.invoke(target, args);
//4.时间统计结束
System.out.println("记录结束时间");
return retVal;
}
public static void main(String[] args) {
PayService target= new AliPayService();
PayService proxy= (PayService) Enhancer.create(target.getClass(),new
PayServiceCGLIBInterceptor(target));
proxy.pay();
}
}

JDK CGLIB 的区别

1. JDK 实现,要求被代理类必须实现接口,之后是通过 InvocationHandler Proxy ,在运行时动态的在内存中生成了代理类对象,该代理对象是通过实现同样的接口实现(类似静态代理接口实现的方式),只是该代理类是在运行期时,动态的织入统一的业务逻辑字节码来完成。
2. CGLIB 实现,被代理类可以不实现接口,是通过继承被代理类,在运行时动态的生成代理类对象。

总结

AOP 是对某方面能力的统一实现,它是一种实现思想, Spring AOP 是对 AOP 的具体实现, Spring AOP 可通过 AspectJ (注解)的方式来实现 AOP 的功能, Spring AOP 的实现步骤是:
1. 添加 AOP 框架支持。
2. 定义切面和切点。
3. 定义通知。
Spring AOP 是通过动态代理的方式,在运行期将 AOP 代码织入到程序中的,它的实现方式有两种: JDK Proxy 和 CGLIB

 文章来源地址https://www.toymoban.com/news/detail-615204.html

到了这里,关于Spring AOP 的概念及其作用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入解析Spring的IOC与AOP及其在项目中的应用

    在现代的软件开发中,为了提高代码的可维护性、可扩展性以及降低代码的耦合度,使用设计模式和面向切面编程(AOP)成为了程序员们常用的技术手段。Spring作为一个优秀的Java开发框架,提供了IOC和AOP两个核心特性,极大地简化了开发工作。本文将深入探讨Spring的IOC和AO

    2024年02月13日
    浏览(38)
  • Java spring Aop实战

    Spring AOP 1. 实战 1.实战 创建工程和依赖 数据库建表 实体类 Mapper 接口 方法一 方法二 Service 包 接口1: 实现接口 Mapper Mapper 1 Mapper 2 配置xml文件 Xml 1 Xml 2 Spring 配置文件 Mybatis配置文件 测试类 数据库结果 测试2 测试3 不符合业务逻辑,加入事物 头文件 只能在service实现类加 重

    2024年02月15日
    浏览(27)
  • java Sping aop 以及Spring aop 的应用事务管理

    线程死锁概念和如何避免死锁的发生: 线程的通信 wait notify() notify():---Object类 线程的状态: NEW ---start()---就绪状态---CPU时间片---运行状态 RUNNABLE]- --sleep()--- TIMED_WAITING ---wait()---- WAITING ----sysn---Blocked---- 终止状态[T] 线程池: 常见的线程池种类: 4种和原始 在软件业,AOP为Aspect Ori

    2024年02月12日
    浏览(32)
  • Spring入门&控制反转(或依赖注入)&AOP的关键概念& 多配置文件&与web集成

    目录 1. 什么是spring,它能够做什么? 2. 什么是控制反转(或依赖注入) 3. AOP的关键概念 4. 示例 4.1 创建工程 4.2 pom文件 4.3 spring配置文件 4.4 示例代码 4.4.1 示例1 4.4.2 示例2 (abstract,parent示例) 4.4.3 使用有参数构造方法创建javaBean 4.4.4 init-method:指定bean的初始化方法 4.4.5 复杂属

    2024年02月09日
    浏览(30)
  • 8.1Java EE——Spring AOP

            Spring的AOP模块是Spring框架体系中十分重要的内容,该模块一般适用于具有横切逻辑的场景,如访问控制、事务管理和性能监控等 一、AOP概述         AOP的全称是Aspect Oriented Programming,即面向切面编程。和OOP不同,AOP主张将程序中相同的业务逻辑进行横向隔离,

    2024年02月16日
    浏览(33)
  • Java EE 突击 14 - Spring AOP

    这个专栏给大家介绍一下 Java 家族的核心产品 - SSM 框架 JavaEE 进阶专栏 Java 语言能走到现在 , 仍然屹立不衰的原因 , 有一部分就是因为 SSM 框架的存在 接下来 , 博主会带大家了解一下 Spring、Spring Boot、Spring MVC、MyBatis 相关知识点 并且带领大家进行环境的配置 , 让大家真正用好

    2024年02月11日
    浏览(27)
  • JAVA:使用 Spring AOP 实现面向切面编程

    1、简述 在现代的软件开发中,面向切面编程(AOP)是一种重要的编程范式,它允许我们将横切关注点(如日志记录、性能监控、事务管理等)从应用程序的核心业务逻辑中分离出来,以提高代码的模块化和可维护性。Spring 框架提供了强大的 AOP 支持,使得我们可以轻松地实

    2024年04月13日
    浏览(31)
  • 【Java面试】Spring中的IOC和AOP

    IOC:控制反转也叫依赖注入。利用了工厂模式 将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的

    2024年02月10日
    浏览(34)
  • 【Java 初级】Spring核心之面向切面编程(AOP)

    tip:作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。 💕💕 推荐: 体系化学习Java(Java面试专题) AOP(面向切面编程)是一种编程范式,用于将横切关注点(如日志记录、性能统计等

    2024年02月04日
    浏览(35)
  • Spring5系列学习文章分享---第三篇(AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式))

    开篇: 欢迎再次来到 Spring 5 学习系列!在这个博客中,我们将深入研究 Spring 框架的AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式)。 概念 什么是AOP (1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的

    2024年01月24日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包