发布于 2026-01-06 2 阅读
0

Java 和 SpringBoot 编程范式中的面向切面编程 为什么选择 AOP? Maven 依赖建议 切面 启用 AOP 结论 面向切面编程演示 延伸阅读 由 Mux 呈现的 DEV 全球展示挑战赛:展示你的项目!

使用 Java 和 SpringBoot 进行面向切面编程

编程范式

为什么选择AOP?

Maven依赖项

建议

切点

方面

启用AOP

结论

面向切面编程演示

延伸阅读

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

这篇博客涵盖了面向切面编程(AOP)的基础知识。我将展示一个简单的AOP示例:像记录REST调用这样的常见任务可以用一个Advice来通用地定义,然后可以通过切面将其应用到代码中的各种目标位置(即所谓的切入点

心急的朋友:你们可以在我的Github仓库里找到最终结果🏎️

GitHub 标志 pmgysel / aop-demo

面向切面编程演示

编程范式

早在 1996 年Java 1.0 发布时,Java 开发人员都对面向对象编程(也称为 OOP)充满热情。虽然 OOP 是 Java 的基础驱动力之一,但自那时以来,这门编程语言本身已经取得了长足的进步,现在支持多种编程范式

以下是 Java 支持的主要编程范式列表(按历史顺序排列):

  • 程序化编程
  • 面向对象编程(OOP)
  • 函数式编程
  • 面向切面编程(AOP)

本文将重点介绍面向切面编程 (AOP),并展示如何创建切面。您将学习 AOP 的基础知识以及如何将其与SpringBoot结合使用。

为什么选择AOP?

大多数大公司都有编程规范,我们公司也不例外。其中一条规范规定,每次REST端点执行都必须记录日志(Java 方法名 + 参数)。

以下是解决方法:



@RestController
public class MyRestController {
  @GetMapping(path = "/api/hello/")
  public String hello() {
    System.out.println("Method [hello] gets called with 0 parameters");
    return "Hello world!";
  }
}


Enter fullscreen mode Exit fullscreen mode

上面的代码片段执行以下操作:

  • @RestController确保 SpringBoot 知道此类包含 REST 端点。
  • @GetMapping:一种响应 HTTP GET 请求的方法
  • System.out.println(...)请遵守上述编码准则
  • return值:该方法仅返回一个字符串类型的问候消息。

在实际应用中,你会在许多不同的类中遇到许多这样的 REST 调用。在所有这些方法中都使用完全相同的日志记录方式会非常繁琐。此外,如果编码规范稍有变化,你还需要在每个方法中修改日志消息。

这时AOP就派上用场了:借助AOP,我们可以在代码的不同位置轻松添加通用功能,而不会干扰现有代码。用学术术语来说,AOP的核心在于分离横切关注点。🤓 更通俗易懂地说,AOP实现了跨对象通用任务的模块化。😎

Maven依赖项

要在SpringBoot中使用AspectJ 注解进行AOP 开发,我们需要在代码中导入以下依赖项pom.xml



<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
</dependency>


Enter fullscreen mode Exit fullscreen mode

建议

让我们创建一个函数,以通用的方式执行所需的日志记录:



public void logMethodExecution(JoinPoint joinPoint) {
  String method = joinPoint.getSignature().getName();
  String params = Arrays.toString(joinPoint.getArgs());
  System.out.println("Method [" + method + "] gets called with parameters " + params);
}


Enter fullscreen mode Exit fullscreen mode

这个通用函数被称为Advice(通知) 。请注意,它可以记录任何方法的名称和参数;让我们逐步分析 Advice:

  • JoinPoint此对象包含有关连接点的所有信息,也就是我们将要插入切面的“位置”。在本例中,这将是我们要为其创建日志消息的REST 方法。
  • joinPoint.getSignature()joinPoint.getArgs()提取方法签名以及调用参数
  • System.out.println(...)执行必要的日志记录

切点

那么,我们应该把上面的 Advise 方法插入到哪里呢?我们希望跟踪每个 REST 端点。虽然有很多方法可以标记 REST 端点,但我们选择使用自定义注解来定义切入点



@Before("@annotation(LogMethod)")
public void logMethodExecution(JoinPoint joinPoint) {...}


Enter fullscreen mode Exit fullscreen mode

如您所见,切入点定义只有一行代码:

  • @Before我们在 REST 调用得到响应之前运行 Advice。
  • @annotation我们通过注解来标记切入点。
  • LogMethod这是我们自定义注解的名称

现在我们可以用自定义注解来标记我们的 REST 方法了:



@LogMethod
@GetMapping(path = "/api/hello/")
public String hello() {
  return "Hello world!";
}


Enter fullscreen mode Exit fullscreen mode

请注意,我们在 REST 方法前添加了注解@LogMethod。此外,我们移除了方法内部的日志记录,现在由切面(Aspect)来完成。

方面

一个方面(Aspect)是由一个切入点(Pointcut)加上一个建议(Advice)构成的。所以,让我们把这两者结合起来,得到:



@Aspect
@Component
public class LoggingAspect {

  @Before("@annotation(LogMethod)")
  public void logMethodName(JoinPoint joinPoint) {
    String method = joinPoint.getSignature().getName();
    String params = Arrays.toString(joinPoint.getArgs());
    System.out.println("Method [" + method + "] gets called with parameters " + params);
  }
}


Enter fullscreen mode Exit fullscreen mode

我们目前掌握的情况如下:

  • @AspectSpringBoot 要求所有切面都位于带有@aspect注解的类中。
  • @Before(...): 切入点
  • logMethodName(...){...}建议

所以我们在这里所做的,就是将之前展示的 Pointcut 表达式和 Advice 结合起来,然后把所有内容封装到一个类中。开香槟庆祝吧,我们的 Aspect 已经完成并可以正常工作了🥂

启用AOP

最后,我们需要为 Spring 配置启用 AspectJ



@Configuration
@EnableAspectJAutoProxy
public class AspectConfig {

}


Enter fullscreen mode Exit fullscreen mode

请记住,在使用 Spring 时,我们需要能够操作 Bean。目前,我们的@RestController类只包含 REST 调用逻辑,而不包含 Advice。Spring 可以为这类 Bean 创建包含此附加逻辑(Advice)的代理@EnableAspectJAutoProxy,这是通过以下方式实现的:

结论

就这样!你现在就拥有了一个完整的AOP示例😀💪🍾

我们实现了一个通知机制,当带有注解的方法@LogMethod执行时就会运行。得益于我们的面向切面编程(AOP)方法,我们可以将此注解添加到未来的 REST 方法中,这些方法随后也会收到相同切面的通知!

请查看Github上的完整示例:

GitHub 标志 pmgysel / aop-demo

面向切面编程演示

面向切面编程演示

这是一个使用面向切面编程 (AOP) 的简单 Web 服务。REST 方法由多个切面提供建议。

依赖关系

  • Java JDK 15
  • Maven:
    • spring-boot-starter-aop
    • aspectjweaver

REST 调用方面

  • 日志方法名称和参数
  • 记录方法持续时间

用法

  • 编译并运行Web服务:
mvn clean install
mvn spring-boot:run
Enter fullscreen mode Exit fullscreen mode
  • REST 调用示例:
GET http://localhost:8080/api/greeting/{name}
GET http://localhost:8080/api/order/{menu}
Enter fullscreen mode Exit fullscreen mode

示例宽高比输出

Method [greeting] gets called with parameters [John]
Exeution took [21ms]
Enter fullscreen mode Exit fullscreen mode

这个 GitHub 仓库还包含第二个建议@Around:每次调用 REST 方法时,我们都会记录执行时间。这对于衡量、监控和比较不同 REST 端点的性能非常有用。

感谢阅读,如果您有任何反馈或疑问,请留言!😀


延伸阅读

如果你感兴趣,这里还有一些相关阅读材料:

AOP入门和通知类型在我们的示例中,我们使用了@Before
类型的通知。或者,您可以使用@After @Around@AfterThrowing

切入点是与一组连接点匹配的谓词。我们使用了注解驱动的切入点,但 Spring 支持更多指示符类型。例如,Spring 支持execution方法名必须匹配给定模式的切入点。

AOP 代理:Spring 官方文档中的解释。

文章来源:https://dev.to/pmgysel/aspect-oriented-programming-with-java-and-springboot-2nlg