JavaEE进阶:SpringAOP

一.AOP概述

在学习完Spring的统一功能之后,我们就要进入到SpringAOP的学习.

AOP是Spring框架的第二大核心.

AOP,全名叫Aspect Oriented Programming,翻译过来就是面向切面编程

简单来说AOP是一种思想,是对某一类事情的集中处理

就好比之前学过的拦截器,就是登入校验这一类问题的统一处理.

还有统一结果返回,统一异常处理,这些都算做AOP的实现.

但是spring考虑不到所有的情况,所以有些情况下需要自己实现AOP.

比如我现在要记录每个方法耗时的时间,又或者有别的什么需求.

二.SpringAOP快速入门

假如不使用AOP,我们要记录每个方法的运行时间,就需要在方法开头记个时间戳,然后return前记录个时间戳然后求差.这样子每个方法都得去写,不仅麻烦,还容易漏.

接下来我们用AOP来解决这个问题.

2.1 引入AOP依赖

在pom.xml文件中添加依赖

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

2.2 编写AOP程序

记录controller中的每个方法的执行时间.

AOP程序,主要通过@Aspect注解和@Around注解来实现.

@Aspect注解是用来告诉spring这是一个切面类.

@Around注解表示环绕通知,在目标方法前后都会被执行.括号内的内容表示对哪些方法进行功能增强(作用范围).

ProceedingJoinPoin.proceed()方法表示让原始方法执行.

接下来我们测试一下.

运行接口就能看到每个controller方法的耗时了.

三.SpringAOP详解

3.1 SpringAOP核心概念

3.1.1 切点

切点的作用就是来告诉程序对哪些方法进行增强,也就是AOP的作用范围.

下面这个就是切点表达式

3.1.2 连接点

所有满足切点表达式的方法,都叫做连接点,

以上面切点表达式为例,所有com.example.demo.controller下的方法都是连接点.

3.1.3 通知

通知就是具体要做的工作,指那些重复的逻辑,也就是共同的功能.

比如在上述程序中,记录方法的耗时,就是通知.

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

3.1.4 切面

切面 = 切点+通知

通过切面能描述当前AOP程序的作用范围和进行什么样的的操作

下面这个就是切面

3.2通知类型

通知不止有@Around一种类型.@Around是环绕通知,就是在目标方法前后都执行.

SpringAOP的通知类型有以下几种:

我们来看下这些通知的执行顺序

java 复制代码
public class AspectDemo {
    @Around("execution(* com.example.demo.controller.*.*(..))")
    public Object AroundDemo(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("Around方法开始执行");
        Object result = joinPoint.proceed();
        log.info("Around方法执行完毕");
        return result;
    }

    @Before("execution(* com.example.demo.controller.*.*(..))")
    public void BeforeDemo() throws Throwable {
        log.info("Before方法执行");
    }

    @After("execution(* com.example.demo.controller.*.*(..))")
    public void AfterDemo() throws Throwable {
        log.info("After方法执行");
    }

    @AfterReturning("execution(* com.example.demo.controller.*.*(..))")
    public void AfterReturningDemo() throws Throwable {
        log.info("AfterReturning方法执行");
    }
    @AfterThrowing("execution(* com.example.demo.controller.*.*(..))")
    public void AfterThrowingDemo() throws Throwable {
        log.info("AfterThrowing方法执行");
    }
}

运行登入接口程序,观察日志

可以看到在正常情况下.AfterThrowing方法不会被执行,现在看看抛出异常的情况

可以看到在异常情况下Around执行只会执行一半,这个不是绝对的,如果在finally里面写,也是会执行的.

注意:

3.3@PointCut

上述代码存在一个问题,就是存在大量的切点表达式.

Spring提供了**@PointCut注解,把公共的切点表达式提取出来,在需要使用的时候在引入即可.**

使用pt()来表示切点表达式,这样在之后使用的时候不需要写那么多,同时在需要修改的时候,只需要改一处即可.

当切点定义使用private修饰的时候,只能在当前切面类使用,如果其他切面类也要使用切点定义,就需要将private改为public.引用方式为:全限定类名.方法名()

3.4切面优先级@Order

当我们一个项目中定义了多个切面类的时候,并且这些切面类同时匹配到了同一个方法,这时候这些切面类的顺序会是什么样子?

我们来定义三个切面类.

此时,运行程序,访问接口.可以看到还是有顺序的,这个顺序是按照字母和数字来排序的.

但是我们的类名还是有更多的意义,所以不方便随意改动,此时又想要按照我们想的顺序来执行,就需要用到@Order注解.

再次运行程序.可以看到此时顺序发生变化了.

从这个结果来看,@Order里面的数字越小,执行顺序越优先.

3.5 切点表达式

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

1.execution(......):根据方法的签名来匹配

2.@annotation(......):根据注解匹配

3.5.1 execution表达式

execution()是最常用的切点表达式,用来匹配方法.

语法:

3.5.2 @annotation

execution表达式更适用于有规则的,就好比某个包下面的所有类,或者同一个名字的包,类...

@annotation注解就不同了,他可以适用于无规则的多个方法

举个简单的例子,我们可以自定义一个注解,然后让加上这个注解的方法实现AOP

3.5.2.1 自定义注解@MyAspect

创建一个注解类

然后用**@Target表示Annotation所修饰的对象范围**,也就是说这个注解可以用在方法上还是类上.

@Retention注解指Annotation被保留的时间长短,也就是注解的生命周期

此时就已经定义完一个注解了.

3.5.2.2 切面类

定义完注解之后,我们需要使用@annotation切点表达式定义切点,只对@MyAspect注解生效.

我们需要把@Around注解里面的切点表达式改成

此时,只有加了@MyAspect注解的方法才能记录耗时.

分别运行t1,t2,可以看到只有加了@MyAspect注解的方法才能生效

相关推荐
Wang's Blog1 小时前
Java框架快速入门: Spring Security+OAuth2之方法级安全注解
java·安全·spring
JavacKaka1 小时前
LiteFlow规则引擎实战博客-2026-09-09
java
学渣超1 小时前
记一次复杂业务功能重构——从过程式长链路,到模板方法构建体系
java·架构·代码规范
Bs_MoneyMagnet2 小时前
基于springboot+vue的旅游景区点评系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·旅游
夜不会漫长2 小时前
C++:类和对象(2)
java·javascript·c++
IT毕设实战小研2 小时前
基于大数据的国内主要农作物产量趋势分析与可视化
android·java·大数据·django·课程设计
星辞秋2 小时前
Java 入门实战:从零搭建环境到写出第一个可用的命令行工具
java
ch.ju2 小时前
Java—idea知识:如何创建新项目
java·开发语言·intellij-idea
土司大王2 小时前
LeetCode hot100——74.搜索二维矩阵:Java 二分模板
java·算法·leetcode