赞
踩
在这篇文章中,我们将会使用Spring中的AOP支持来实现一个自定义的AOP注解(AOP annotation)。
首先,我们会给出AOP的一个高级(high-level)概述,解释它是什么和它的优点。接着,我们会一步一步地实现自己的注解,从而逐渐地对AOP有更深入的了解。
我们将会获得(outcome):更好地理解AOP,以及将来创建自定义Spring注解的能力。
快速总结一下,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
}
在上面,我们的关注点应是它是非侵入性的(non-invasiveness)。通过使用注解元数据,我们的核心业务逻辑没有被事务代码污染。这使单独推理、重构和测试更容易。
有时,开发Spring应用程序的人将此看做“Spring魔法”,因为不必过多考虑它怎样工作的细节。实际上,发生的事情并不是特别复杂。不过,一旦我们完成本文中介绍的步骤,我们将能创建自己的自定义注解,从而理解AOP,并做到举一反三(leverage)。
首先,让我们添加用到的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>
请注意,我们已经包含了AOP starter,它引入了我们开始实现切面(aspect)所需的库。
个人注:我使用spring initializr添加依赖时,并没有找到关于aop的依赖,其实,我们只需要把上面的starter aop依赖添加进pom.xml中即可。
我们将要创建的注解会用来记录一个方法的运行时间。让我们创建它:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
虽然是一个相对简单的实现,但值得注意的是这两个元注释的用途。
@Target
注解告诉我们自己的注解(也就是LogExecutionTime)适用于哪里。这里我们使用ElementType.Method
,这意味着它仅仅对方法可用。如果我们尝试使用这个注解在任何别的地方,那么我们将不能编译通过。这种行为是有道理的,因为我们的注解将用于记录方法执行时间。
而@Retention
只是说明注解是否可用于JVM的运行时(runtime)。默认它是不能用的,因此Spring AOP将不会检测到这个注解。这就是我们配置它的原因。
现在,我们有个自己的注解,让我们创建自己的切面。这只是将封装我们的横切关注点(cross-cutting concern)的模块,我们的例子是方法运行时间记录。它是一个带有@Aspect
注解的类:
@Aspect
@Component
public class ExampleAspect {
}
我们已经包含了@Component
注解,因为我们的类也需要是一个能被检测到的Spring bean。本质上,这是我们将实现注入自定义注解逻辑的类。
现在,让我们创建pointcut和advice。这将是一个存在于我们切面带注解的方法:
@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
return joinPoint.proceed();
}
个人注:所以,这个应该放在
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/615701
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。