Spring AOP 面向切面编程(上)

简介: Spring AOP 面向切面编程(上)

一. 什么是 Spring AOP



关于什么是 Spring AOP. 当我翻到官方文档的时候也是一惊


Let us begin by defining some central AOP concepts and terminology. These terms are not Spring-specific… unfortunately, AOP terminology is not particularly intuitive; however, it would be even more confusing if Spring used its own terminology.


什么意思呢 ? 大概意思就是 Spring 官方说这些概念不是 Spring 独有的, 而是已经存在了的. 并且这些术语都不是很直观, 如果使用 SPring 自己的术语, 将会让人更加困惑.

当说到这的时候, 相信你已经知道了. 不是 Spring 特有的概念这不是关键, 主要的是连官方都说了 Spring AOP 的概念非常抽象, 理解起来会有一定的难度. 大致来看看到底什么是 SPring AOP, 它又到底是能做些什么 ?


1. Spring AOP 作用


现在无论是什么系统或者应用, 在使用之前都需要进行用户登陆验证. 除了登陆以及注册一面不需要验证以外, 其余功能基本都需要登陆才能使用. 因此想要完成这件事, 在之前我们是在所有需要验证的页面中通过 Controller 来登陆验证.


当你的功能越来越多之时, 你需要写的登陆验证也越来越多, 但是这些方法又是相同的, 会无故增加你很多代码修改和维护的成本. 那么如何将它单独抽离出来做成一个大家都能使用的功能, 让其他页面直接调用就能判定登录就是目前需要解决的.


在上面的基础之上, Spring AOP 的诞生就让其很好地进行了解决. 那么现在能解释什么是 Spring AOP 了吧 ?


AOP 是一种思想, Spring AOP 它是一种框架, 它提供了一种对 AOP 的具体实现. 类似于我们之前学的 Ioc 和 DI 之间的关系. 简单来说, AOP 干的是将某一个统一的功能集中处理.


  • 统一的用户登录
  • 统一的日志记录
  • 统一的方法执行时间统计
  • 统一的返回格式
  • 统一的异常处理
  • 统一的事务开启和提交


除了这些, 还有很多. 也就是说使用 AOP 可以扩充多个对象的某种能力. ( 张三、李四都具有相同的登陆能力等等 ).


2. AOP 的组成


2.1 Aspect 切面


什么是切面 ?


指的是横切多个类的一种模块. 在 Spring 中切面用的就是普通的类 ( XML 或者 @Aspect 注解配置 ).这么一听好像很抽象, 比如我们刚刚说的登陆页面模块, 查看他人文章, 发布文章等等, 在执行自己对应的功能之前进行登录验证. 那么为了处理这个问题, 创建了一个普通类来集中处理. 而这个类就是切面.


这里的多个类就是执行对应的功能类, 而横切就是登陆. 把登陆创建成一个集中模块来处理就是切面.


2.2 Joint point

Joint Point : 连接点, 表示要横切的方法. 就是执行 AOP 功能的所有方法


例如上面登陆说的, 查看他人文章和发布文章的功能方法都是连接点.


2.3 Pointcut 切点

所谓的切点就是从哪里开始入手的意思. 也就是对于那些连接点起作用.


例如上面登陆说的, 可以从查看他人文章和发布文章这两个功能切入, 也就是定义的 AOP 只对这两个起作用, 而对于注册功能是不起作用的, 因为它不需要实现登录检验.


2.4 Advice 通知

通知, 是非常复杂的. 它里面定义了切面是什么, 什么时候使用. 描述了切面要完成的工作, 还解决什么时候执行这个工作的问题.


关于 Advice 通知它有很多类型, 可以在方法上使用一下注解, 会设置改方法为通知方法, 在满足条件以后会通知本方法进行调用


2.4.1 前置通知 : @Before

通知方法会在目标方法 ( 也就是连接点 ) 调用之前执行


2.4.2 后置通知 : @After

通知方法会在目标方法 ( 连接点 ) 调用之后执行.

PS : 无论连接点是正常结束还是异常结束都会执行


2.4.3 返回通知 : @AfterReturning

通知方法会在目标方法 ( 连接点 ) 返回之后调用

PS : 需要方法正常 return 并且没有抛出异常


2.4.4 异常通知 : @AfterThrowing

通知方法会在目标方法 ( 连接点 ) 异常之后调用


2.4.5 环绕通知 : @Around

通知包裹了被通知的方法, 在被通知的方法 ( 连接点 ) 通知之前和调用之后执行的自定义的行为


二. Spring AOP 实现



知道了什么是 Spring AOP 还有 AOP 的组成等等, 现在就可以来简单实现一个统一的登陆功能了.


1. 添加 Spring AOP 框架


因为我们的 Spring Boot 框架没有内置 Spring AOP 因此, 我们需要手动引入依赖. 而 Spring 框架中是有 Spring AOP 依赖的. 但我此处是 Spring Boot 项目. 需要引入 Spring Boot 框架支持的 Spring AOP 框架.


Maven 仓库 中进行引入依赖, 一定是引入的 Spring Boot 支持的 Spring AOP 依赖e488ba889d44d5153cc30edc7b11cc8c.png


选择一个相应的版本进行 pom.xml 中引入依赖即可

<!--    添加的是 Spring Boot 项目的 AOP 依赖, 而原生的 AOP 依赖在 Spring 中使用   -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.7.12</version>
    </dependency>


2. 定义切面


引入好了 Spring AOP 以后, 对登陆功能进行统一处理, 需要先建立切面, 也就是前所说的一个普通类来集中处理

@Aspect // 添加切面注解
    @Component // 随 Spring 框架启动而注入
    // 创建切面 - 关于某一操作的统一类
    public class UserAOP {
    }


可以看到, 我添加了 @Aspect 和 @Component 注解.

  • @Aspect 注解也就是切面注解, 表明我们当前这个普通类是一个切面
  • @Component 注解不陌生, 将其添加到我们的 Spring 容器当中供外部使用. 为什么呢 ?


原因也很简单就是为了在 Spring 框架启动时就注入, 否则其他功能进行访问时, 还未成功加载, 就无法进行统一的处理了.


3. 定义切点


切点我们刚刚也说了, 它是对我们的连接点进行匹配的, 看那些连接点是我们需要处理的, 那些是我们不需要处理的, 从而提高效率. 并且切点是必须定义在切面里的

@Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void doPointcut() {
        // 切点只是为了配置规则, 并非具体实现. 因此为空方法
    }


@Pointcut 切点注解, 里面需要配置 execution 也就是需要处理的

而里面配置就是我们具体需要匹配的连接点, 相当于拦截的规则. 而这里面是如何设置的, 采用的是 aspectj 的语法


3.1 aspectj 语法


Aspectj 支持的三种通配符 :

1.* : 匹配任意字符, 只匹配一个元素 ( 包, 类, 方法, 或者方法参数 )**

2. … : 匹配任意字符, 可以匹配多个元素, 在表示类的时候必须和 * 联合使用

3. + : 表示按照类型匹配指定类的所有类, 必须跟在类名后面


如 com.example.demo.User + 这就表示继承 com.example.demo 包底下的 User 类的所有子类, 也包括 User 本身

execution 的组成包括 : ( 修饰符 + 返回类型 + 包.类.方法(参数) + 异常 )


  • 修饰符

在 aspectj 中 修饰符一般可以省略. 如果不省略的话, 可以进行声明, 例如

( public + 返回类型 + 包.类.方法(参数) + 异常 )

当然, 除了指定特定返回值以外, 还可以使用通配符一次性匹配所有的修饰符

( * + 返回类型 + 包.类.方法(参数) + 异常 )


  • 返回类型

返回值是不可以省略的. 和修饰符一样, 可以指定返回值或者使用通配符


  • 包.

固定包 : com.example.demo

固定包底下的任意子包 : com.example.demo.*.service

即 com.example.demo 固定包下面的 service 包

固定包底下的所有包 : com.example.demo…

即 com.example.demo 固定包下的所有包, 包括本身


  • 类.

指定类 : UserController

Controller : 以 Controller 结尾
User
: 以 User 开头


  • 方法

方法名不能省略

fun : 固定方法

fun* : 以 fun 开头的方法

*fun : 以 fun 结尾的方法

通配符 * : 任意方法


  • 参数

( ) : 无参

( int ) : 指定 int 类型参数

( int, int ) : 指定两个 int 类型的参数

( … ) : 表示任意参数


  • 异常

异常一般省略不写


3.2 实现切点


了解了 Aspectj 语法以后, 现在就可以在 @Pointcut 注解里配置 execution 拦截规则了.


例如, 我想拦截 com.example.demo.controller 包下的 UserController 类任意参数并且返回值任意的所有方法

@Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void doPointcut() {
        // 切点只是为了配置规则, 并非具体实现. 因此为空方法
    }


可以看到, 我在里面提供了一个没有方法体的空方法 doPointcut( ), 需要注意的是, **切点它只是为连接点是否执行 AOP 设置匹配规则的, 并非具体的连接点功能实现. **


4. 建立连接点


由于刚刚的切点配置的是 com.example.demo.controller.UserController , 因此起作用的连接点只能在这里面, 而在这外面的连接点都是不起作用的.


在指定的类里写我们的连接点和具体连接方法实现, 我们上面说的查看文章和发布文章

@RequestMapping("/user/article")
    public String login1() {
        System.out.println("执行了查看文章功能中的登陆检验");
        return "Spring AOP";
    }


@RequestMapping("user/write")
    public String login2() {
        System.out.println("执行了写文章功能中的登录检验");
        return "Spring AOP";
    }


5. 建立通知


为了更方便我们查看是否真的执行了 Spring AOP 的统一登录功能, 我们可以在切面中实现一个通知来帮助我们观察, 下面就举例一个前置通知


// 配置前置通知
@Before("pointcut()") // 里面填写针对那个切点的通知, 可以有多个切点
    public void doBefore() {
    System.out.println("执行 before 前置通知 : 登陆检验" );
}


通知在我们上面的 AOP 组成中说到, 它里面定义了切面是什么, 什么时候使用. 这里的定义了切面指的就是是因为我们通知的一般主体是切面. **可以理解为这个通知就是通知这个统一的处理去干什么 ( 切点 - 拦截那些内容 ), 什么时候执行( 在连接点之前, 之后等, 具体看什么通知 ) **


6. 检验统一登录


当我们想使用写文章和查看文章功能的时候, 需要先经过 Spring AOP 的统一登录检验, 来看看我们的这两个路由方法是否能正确在 Spring AOP 中执行


  • 查看文章功能检验统一登录

f3ce50be80d1d5c06c605d5da1339373.pngceb1bf03d468ef51ad04e06a410f06bf.png


可以看到, 当我们使用查看文章时, 它便会进行指定的统一登录检验, 触发切面中的通知方法.


  • 写文章功能

6aef8956fec8c2faf32fd7508322bfef.pngcc73236065a53941d5672691f8046ffb.png


同样的, 当我们执行写文章功能时, 它也会先进行统一登录的检验, 触发切面中的通知方法


当然, 上面还是不够直观, 我们可以创建一个切点以外 ( 和切点路径不匹配的 ) 的连接点

我在 controller 包底下建立了一个 RegisterController 类, 来表示我的注册类


@RestController
    public class RegisterController {
        @RequestMapping("/user/reg")
        public String register() {
            System.out.println("执行注册功能 -> ");
            return "Spring AOP";
        }
    }


显然, 我们的注册方法是不需要经过统一的登陆处理的. 因此预期它不会触发我们切面中的通知方法

d505ddb99e5a5c942bb78f6306b47045.png

aad5a222f4cb9553dacdd5f0aa5c2505.png


可以看到, 我们虽然执行了注册功能, 但是并没有触发通知方法, 也就是说并没有进行统一的登陆检验.


相关文章
|
11天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
17天前
|
安全 Java 编译器
什么是AOP面向切面编程?怎么简单理解?
本文介绍了面向切面编程(AOP)的基本概念和原理,解释了如何通过分离横切关注点(如日志、事务管理等)来增强代码的模块化和可维护性。AOP的核心概念包括切面、连接点、切入点、通知和织入。文章还提供了一个使用Spring AOP的简单示例,展示了如何定义和应用切面。
53 1
什么是AOP面向切面编程?怎么简单理解?
|
1月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
37 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
16天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
27 1
|
22天前
|
XML Java 开发者
论面向方面的编程技术及其应用(AOP)
【11月更文挑战第2天】随着软件系统的规模和复杂度不断增加,传统的面向过程编程和面向对象编程(OOP)在应对横切关注点(如日志记录、事务管理、安全性检查等)时显得力不从心。面向方面的编程(Aspect-Oriented Programming,简称AOP)作为一种新的编程范式,通过将横切关注点与业务逻辑分离,提高了代码的可维护性、可重用性和可读性。本文首先概述了AOP的基本概念和技术原理,然后结合一个实际项目,详细阐述了在项目实践中使用AOP技术开发的具体步骤,最后分析了使用AOP的原因、开发过程中存在的问题及所使用的技术带来的实际应用效果。
49 5
|
12天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
25 0
|
1月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
69 2
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
127 9
|
1月前
|
Java 数据库连接 Spring
【2021Spring编程实战笔记】Spring开发分享~(下)
【2021Spring编程实战笔记】Spring开发分享~(下)
26 1
|
1月前
|
Java 容器
AOP面向切面编程
AOP面向切面编程
42 0