Spring 中的Advice类型介绍

2023-10-27

Spring 中的 Advice 类型介绍

翻译原文链接 Introduction to Advice Types in Spring

1. 概述

在本文中,我们将讨论可以在 Spring 中创建的不同类型的 AOP 通知。

In this article, we’ll discuss different types of AOP advice that can be created in Spring.

通知是切面在特定连接点采取的行动。不同类型的通知包括 环绕前置后置 通知。切面的主要目的是支持横切关注点,例如日志记录、分析、缓存和事务管理。

Advice is an action taken by an aspect at a particular join point. Different types of advice include “around”, “before” and “after” advice. The main purpose of aspects is to support cross-cutting concerns, such as logging, profiling, caching, and transaction management.

如果您想更深入地了解切点表达式,请查看前面的介绍(Spring 中的切点表达式介绍)。

And if you want to go deeper into pointcut expressions, check out the previous intro to these.

2. 启用通知

Spring 中,您可以使用 AspectJ 注解声明通知,但您必须首先将 @EnableAspectJAutoProxy 注解应用到您的配置类,这将支持处理标记有 AspectJ@Aspect 注解的组件。

With Spring, you can declare advice using AspectJ annotations, but you must first apply the @EnableAspectJAutoProxy annotation to your configuration class, which will enable support for handling components marked with AspectJ’s @Aspect annotation.

@Configuration
@EnableAspectJAutoProxy
public class AopConfiguration {
    // ...
}

2.1. Spring Boot

Spring Boot 项目中,我们不必显式使用 @EnableAspectJAutoProxy。如果 AspectAdvice 在类路径上,则有一个专用的 AopAutoConfiguration 可以启用 SpringAOP 支持。

In Spring Boot projects, we don’t have to explicitly use the @EnableAspectJAutoProxy. There’s a dedicated AopAutoConfiguration that enables Spring’s AOP support if the Aspect or Advice is on the classpath.

3. 前置通知

顾名思义,该通知在连接点之前执行。除非抛出异常,否则它不会阻止它通知的方法的继续执行。

This advice, as the name implies, is executed before the join point. It doesn’t prevent the continued execution of the method it advises unless an exception is thrown.

(现在我们来)考虑下面的切面,(该切面用来)在调用之前简单记录方法名称:

Consider the following aspect that simply logs the method name before it is called:

@Component
@Aspect
public class LoggingAspect {

    private Logger logger = Logger.getLogger(LoggingAspect.class.getName());

    @Pointcut("@target(org.springframework.stereotype.Repository)")
    public void repositoryMethods() {};

    @Before("repositoryMethods()")
    public void logMethodCall(JoinPoint jp) {
        String methodName = jp.getSignature().getName();
        logger.info("Before " + methodName);
    }
}

The logMethodCall advice will be executed before any repository method defined by the repositoryMethods pointcut.

4. 后置通知

使用 @After 注解声明的 后置通知在匹配的方法执行后执行,无论是否抛出异常。

After advice, declared by using the @After annotation, is executed after a matched method’s execution, whether or not an exception was thrown.

在某些方面,它类似于 finally 块。如果你需要仅在正常执行后触发通知,则应使用 @AfterReturning 注解声明的返回通知。如果你希望仅在目标方法抛出异常时触发您的通知,您应该使用抛出通知,通过使用 @AfterThrowing 注解声明。

In some ways, it is similar to a finally block. In case you need advice to be triggered only after normal execution, you should use the returning advice declared by @AfterReturning annotation. If you want your advice to be triggered only when the target method throws an exception, you should use throwing advice, declared by using the @AfterThrowing annotation.

假设我们希望在创建 Foo 的新实例时通知某些应用程序组件。我们可以从 FooDao 发布一个事件,但这会违反单一职责原则。

Suppose that we wish to notify some application components when a new instance of Foo is created. We could publish an event from FooDao, but this would violate the single responsibility principle.

相反,我们可以通过定义以下的切面来实现这一点:

Instead, we can accomplish this by defining the following aspect:

@Component
@Aspect
public class PublishingAspect {

    private ApplicationEventPublisher eventPublisher;

    @Autowired
    public void setEventPublisher(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    @Pointcut("@target(org.springframework.stereotype.Repository)")
    public void repositoryMethods() {}

    @Pointcut("execution(* *..create*(Long,..))")
    public void firstLongParamMethods() {}

    @Pointcut("repositoryMethods() && firstLongParamMethods()")
    public void entityCreationMethods() {}

    @AfterReturning(value = "entityCreationMethods()", returning = "entity")
    public void logMethodCall(JoinPoint jp, Object entity) throws Throwable {
        eventPublisher.publishEvent(new FooCreationEvent(entity));
    }
}

请注意,首先,通过使用 @AfterReturning 注解,我们可以访问目标方法的返回值。其次,通过声明 JoinPoint 类型的参数,我们可以访问目标方法调用的参数。

Notice, first, that by using the @AfterReturning annotation we can access the target method’s return value. Second, by declaring a parameter of type JoinPoint, we can access the arguments of the target method’s invocation.

接下来我们创建一个监听器,它会简单地记录事件:

Next we create a listener which will simply log the event:

@Component
public class FooCreationEventListener implements ApplicationListener<FooCreationEvent> {

    private Logger logger = Logger.getLogger(getClass().getName());

    @Override
    public void onApplicationEvent(FooCreationEvent event) {
        logger.info("Created foo instance: " + event.getSource().toString());
    }
}

5. 环绕通知

环绕通知围绕一个连接点,例如方法调用。

Around advice surrounds a join point such as a method invocation.

这是(功能)最强大的一种通知。环绕通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续连接点还是通过提供自己的返回值或抛出异常来缩短建议的方法执行。

This is the most powerful kind of advice. Around advice can perform custom behavior both before and after the method invocation. It’s also responsible for choosing whether to proceed to the join point or to shortcut the advised method execution by providing its own return value or throwing an exception.

为了演示它的用法,假设我们要测量方法执行时间。让我们为此创建一个切面:

To demonstrate its use, suppose that we want to measure method execution time. Let’s create an Aspect for this:

@Aspect
@Component
public class PerformanceAspect {

    private Logger logger = Logger.getLogger(getClass().getName());

    @Pointcut("within(@org.springframework.stereotype.Repository *)")
    public void repositoryClassMethods() {};

    @Around("repositoryClassMethods()")
    public Object measureMethodExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.nanoTime();
        Object retval = pjp.proceed();
        long end = System.nanoTime();
        String methodName = pjp.getSignature().getName();
        logger.info("Execution of " + methodName + " took " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
        return retval;
    }
}

当执行 repositoryClassMethods 切点匹配的任何连接点时,会触发此通知。

This advice is triggered when any of the join points matched by the repositoryClassMethods pointcut is executed.

该通知采用 ProceedingJointPoint 类型的一个参数。该参数使我们有机会在目标方法调用之前采取行动。在这种情况下,我们只需保存方法启动时间。

This advice takes one parameter of type ProceedingJointPoint. The parameter gives us an opportunity to take action before the target method call. In this case, we simply save the method start time.

其次,通知返回类型是 Object,因为目标方法可以返回任何类型的结果。如果目标方法为 void,则返回 null。在目标方法调用之后,我们可以测量时间,记录它,并将方法的结果值返回给调用者。

Second, the advice return type is Object since the target method can return a result of any type. If target method is void, null will be returned. After the target method call, we can measure the timing, log it, and return the method’s result value to the caller.

6. 总结

在本文中,我们学习了 Spring 中不同类型的通知及其声明和实现。我们使用基于模式的方法和 AspectJ 注解来定义切面。

In this article, we’ve learned the different types of advice in Spring and their declarations and implementations. We defined aspects using schema-based approach and using AspectJ annotations.

所有这些示例和代码片段的实现都可以在我的 GitHub 项目 中找到。

The implementation of all these examples and code snippets can be found in my GitHub project.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring 中的Advice类型介绍 的相关文章

随机推荐

  • 巨头刷脸补贴大战自伊始就没有停止过

    随 着5G时代的到来 互联网 AI智能 云计算 物联网等技术的成熟 中国财政科学研究院应用学博士后盘和林认为 刷脸支付比密码支付更安全更便捷 我国在移动支付领域相较于其他国家来说一直处于领先地位 支付宝和微信支付两家在这一领域的竞争就从来没
  • QT笔记之QSpinBox和QSlider的封装使用

    文章目录 1 创建QT测试工程 2 右键添加 新建项 3 添加新的Qt Widget Class 叫做MySpinBox Slider QSpinBox和QSlider的组合使用 4 添加好QSpinBox和QSlider两个控件 并且调整
  • 牛顿第二定律沿流线流动粒子 Python 分析(流体力学)

    当流体粒子从一个位置移动到另一个位置时 它通常会经历加速或减速 根据牛顿第二运动定律 作用在所考虑的流体粒子上的合力 必须等于其质量乘以其加速度 F m a mathbf F m mathbf a F ma 实际上 不存在无粘
  • 微信第三方平台的授权过程整理

    最近碰到微信第三方平台这个东西 就研究了下 由于微信官方文档顺序不是很明确 我特别也整理了一下 官方的概述是 公众平台第三方平台是为了让公众号或小程序运营者 在面向垂直行业需求时 可以一键授权给第三方平台 并且可以同时授权给多家第三方 通过
  • Android基础进阶 - 消息机制 之Native层分析,Android面试回忆录

    synchronized this msg markInUse msg when when Message p mMessages boolean needWake 如果消息链表为空 或者插入的Message比消息链表第一个消息要执行的更早
  • Mockito框架@Mock, @InjectMocks注解使用

    最近写项目Junit 使用Junit4框架 测试的数据都要依赖数据库 而好多接口需要调其他的系统 junit4框架完全无法实现测试功能 大佬推荐用Mockito框架 这篇博客用来记录学习Mockito的使用方法 不足欢迎指点 Mock In
  • Dump文件的生成和使用

    1 简介 第一次遇到程序崩溃的问题 之前为单位开发了一个插件程序 在本机运行没有出现问题 但把生成的可执行文件拷贝到服务器上一运行程序 刚进入插件代码 插件服务就崩溃了 当时被这个问题整的很惨 在同事的帮助下了解到 对于程序崩溃 最快的解决
  • qemu图形界面linux,QEMU 简单几步搭建一个虚拟的ARM开发板

    1 安装QEMU 先在Ubuntu中安装QEMU sudo apt get install qemu 1 安装几个QEMU需要的软件包 sudo apt get install zlib1g dev sudo apt get install
  • 在Windows中使用WSL和VS Code搭建出友好的终端开发环境

    使用WSL Windows Subsystem for Linux 这一适用于 Linux 的 Windows 子系统可让开发人员按原样运行 GNU Linux 环境 包括大多数命令行工具 实用工具和应用程序 且不会产生传统虚拟机或双启动设
  • 平面几何-python

    三角形面积 题目描述 平面直角坐标系中有一个三角形 请你求出它的面积 输入描述 第一行输入一个 TT 代表测试数据量 每组测试数据输入有三行 每行一个实数坐标 x y x y 代表三角形三个顶点 1 T 10 3 10 5 x y 10 5
  • 2018年LeetCode高频算法面试题刷题笔记——验证回文串(字符串)

    1 解答之前的碎碎念 这个题还蛮简单的 大概就是考研机试第一题的水平 所以就不写解法了 2 问题描述 给定一个字符串 验证它是否是回文串 只考虑字母和数字字符 可以忽略字母的大小写 说明 本题中 我们将空字符串定义为有效的回文串 示例 1
  • 自媒体账号ID应该怎么取?

    我们都知道 在做自媒体之前 我们需要注册自媒体账号 这时候我们需要给账号取一个名称 一个好的名称能让你吸取更多的粉丝 让读者记忆深刻 取名规范各平台的规则都差不多 所以在入驻平台之前一定要先认真看清各平台名称规范 防止因为名称不规范而不能通
  • 鹏仔暴力刷导航网页排行榜HTML模板,网站如何测压

    现在很多站长都做了导航站 大多数导航站都有网站排行榜 也就是今日浏览榜 月最高浏览榜 总浏览榜等 你页面阅读量越高 那么排名越靠前 曝光的几率就更高 很多站长在某些导航站提交完收录后 手动刷新增加阅读量 真的特别慢 那么本次鹏仔就给大家简单
  • 头文件路径包含问题

    头文件包含两种 系统头文件和自定义头文件 系统头文件不说了 格式统一 自定义头文件在包含的时候要注意路径 其实是头文件与主文件的相对位置关系的问题 ps 另外 LInux和Windows下也有所区别 举4个例子 应该就能看明白了 一 这种情
  • InnoSetup 脚本打包及管理员权限设置

    InnoSetup使用教程 InnoSetup打包安装 脚本详细 1 定义变量 1 define MyAppName TranslationTool 2 define MyAppChineseName 翻译工具 3 define MyApp
  • ios系统下input边框有默认阴影

    修复代码 1 input outline none webkit appearance none 去除系统默认的样式 webkit tap highlight color rgba 0 0 0 0 点击高亮的颜色 2 input appea
  • 深度学习实战11(进阶版)-BERT模型的微调应用-文本分类案例

    文章目录 一 前期工作 导入库包 导入数据 二 模型加载三 模型训练 四 模型测试 大家好 我是微学AI 今天给大家带来一个基于BERT模型做文本分类的实战案例 在BERT模型基础上做微调 训练自己的数据集 相信之前大家很多都是套用别人的模
  • 选择正确的DDoS解决方案:按需云服务

    迁移到云端的优势 与部署独立硬件设备相比 迁移到云端有许多优势 保护基于云的应用程序 托管在云中的应用程序无法通过本地设备保护 因此需要基于云的保护 更大容量 随着容量 DDoS 攻击变得越来越大 许多攻击很容易超过典型企业级 DDoS 缓
  • java HashSet 如何判断元素是否存在

    HashSet不能添加重复的元素 当调用add Object 方法时候 首先会调用Object的hashCode方法判hashCode是否已经存在 如不存在则直接插入元素 如果已存在则调用Object对象的equals方法判断是否返回tru
  • Spring 中的Advice类型介绍

    Spring 中的 Advice 类型介绍 翻译原文链接 Introduction to Advice Types in Spring 1 概述 在本文中 我们将讨论可以在 Spring 中创建的不同类型的 AOP 通知 In this a