当前位置:   article > 正文

实现一个自定义的Spring AOP注解(AOP annotation)

aop annotation

1. 介绍

在这篇文章中,我们将会使用Spring中的AOP支持来实现一个自定义的AOP注解(AOP annotation)。

首先,我们会给出AOP的一个高级(high-level)概述,解释它是什么和它的优点。接着,我们会一步一步地实现自己的注解,从而逐渐地对AOP有更深入的了解。

我们将会获得(outcome):更好地理解AOP,以及将来创建自定义Spring注解的能力。

2. AOP注解是什么?

快速总结一下,AOP表示面向切面编程(Aspect-Orientated Programming)。本质上,这是一种向现有代码添加行为(behavior)而不修改该代码的方式。

对于更详细的AOP介绍,有很多关于AOP pointcut和advice的文章(这是AOP中的两个概念)。这篇文章假设我们对此已基本了解。

我们将在本文实现的AOP是注解驱动的(annotation driven)。你可能对此已经熟悉,如果你使用过Spring的@Transactional注解:

@Transactional
public void orderGoods(Order order) {
    // A series of database calls to be performed in a transaction
}
  • 1
  • 2
  • 3
  • 4

在上面,我们的关注点应是它是非侵入性的(non-invasiveness)。通过使用注解元数据,我们的核心业务逻辑没有被事务代码污染。这使单独推理、重构和测试更容易。

有时,开发Spring应用程序的人将此看做“Spring魔法”,因为不必过多考虑它怎样工作的细节。实际上,发生的事情并不是特别复杂。不过,一旦我们完成本文中介绍的步骤,我们将能创建自己的自定义注解,从而理解AOP,并做到举一反三(leverage)。

3. Maven依赖

首先,让我们添加用到的Maven依赖

对于我们的例子,我们将会使用Spring Boot,因为它的约定由于配置(convention over configuration,Spring Boot特性)方法可以让我们尽快启动和运行:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
</dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

请注意,我们已经包含了AOP starter,它引入了我们开始实现切面(aspect)所需的库。

个人注:我使用spring initializr添加依赖时,并没有找到关于aop的依赖,其实,我们只需要把上面的starter aop依赖添加进pom.xml中即可。

4. 创建我们的自定义注解

我们将要创建的注解会用来记录一个方法的运行时间。让我们创建它:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {

}
  • 1
  • 2
  • 3
  • 4
  • 5

虽然是一个相对简单的实现,但值得注意的是这两个元注释的用途。

@Target注解告诉我们自己的注解(也就是LogExecutionTime)适用于哪里。这里我们使用ElementType.Method,这意味着它仅仅对方法可用。如果我们尝试使用这个注解在任何别的地方,那么我们将不能编译通过。这种行为是有道理的,因为我们的注解将用于记录方法执行时间。

@Retention只是说明注解是否可用于JVM的运行时(runtime)。默认它是不能用的,因此Spring AOP将不会检测到这个注解。这就是我们配置它的原因。

5. 创建我们的Aspect

现在,我们有个自己的注解,让我们创建自己的切面。这只是将封装我们的横切关注点(cross-cutting concern)的模块,我们的例子是方法运行时间记录。它是一个带有@Aspect注解的类:

@Aspect
@Component
public class ExampleAspect {

}
  • 1
  • 2
  • 3
  • 4
  • 5

我们已经包含了@Component注解,因为我们的类也需要是一个能被检测到的Spring bean。本质上,这是我们将实现注入自定义注解逻辑的类。

6. 创建我们的Pointcut和Advice

现在,让我们创建pointcut和advice。这将是一个存在于我们切面带注解的方法:

@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
    return joinPoint.proceed();
}
  • 1
  • 2
  • 3
  • 4

个人注:所以,这个应该放在

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/615701
推荐阅读
相关标签