【译】AOP- Advice Param And Order

名词解释

Advice 通知

Advice Param

Spring 提供完全类型化的Advice,这意味着您可以在Advice签名中声明所需的参数(正如我们之前在返回和抛出示例中看到的那样),而不是一直使用Object[]数组。我们将在本节后面看到如何使参数和其他上下文值可用于Advice主体。首先,我们看一下如何编写通用通知,以了解通知当前通知的方法。

访问当前JoinPoint

任何通知方法都可以将声明类型为 org.aspectj.lang.JoinPoint的参数作为其第一个参数 。请注意,环绕通知必须声明第一个参数为ProceedingJoinPoint,它是JoinPoint 的子类。

JoinPoint接口提供了许多有用的方法:

  • getArgs():返回方法参数。
  • getThis():返回代理对象。
  • getTarget():返回目标对象。
  • getSignature():返回对所通知方法的描述。
  • toString():打印所通知方法的有用描述。

有关更多详细信息,请参阅javadoc。

将参数传递给 Advice

我们已经看到了如何绑定返回值或异常值(在返回和抛出通知之后使用)。要使参数值可用于通知正文,您可以使用args. 如果在args表达式中使用参数名称代替类型名称,则在调用通知时相应参数的值将作为参数值传递。一个例子应该更清楚地说明这一点。假设您要通知执行以Account 对象为第一个参数的 DAO 操作,并且您需要访问通知正文中的帐户。您可以编写以下内容:

java

@Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)")
public void validateAccount(Account account) {// ...
}

args(account,..)切入点表达式的部分有两个目的。首先,它将匹配限制为仅那些方法至少接受一个参数的方法执行,并且传递给该参数的参数是Account. 其次,它通过参数使实际Account对象可用于通知account

另一种写法是声明一个切入点,Account 当它匹配一个连接点时“提供”对象值,然后从通知中引用命名的切入点。这将如下所示:

java

@Pointcut("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)")
private void accountDataAccessOperation(Account account) {}@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {// ...
}

有关详细信息,请参阅 AspectJ 编程指南。

代理对象 ( this)、目标对象 ( target) 和注释 ( @within@target@annotation@args) 都可以以类似的方式绑定。接下来的两个示例显示了如何匹配带有@Auditable 注释的方法的执行并提取审计代码:

示例展示了@Auditable注解的定义:

java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {AuditCode value();
}

以下示例展示了与@Auditable注解方法执行相匹配的通知:

java

@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
public void audit(Auditable auditable) {AuditCode code = auditable.value();// ...
}

Advice 参数和泛型

Spring AOP 可以处理类声明和方法参数中使用的泛型。假设你有一个像下面这样的泛型:

java

public interface Sample<T> {void sampleGenericMethod(T param);void sampleGenericCollectionMethod(Collection<T> param);
}

您可以通过将通知参数绑定到要拦截方法的参数类型来将方法类型的拦截限制为某些参数类型:

java

@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param) {// Advice implementation
}

这种方法不适用于泛型集合。所以你不能定义一个切入点如下:

java

@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
public void beforeSampleMethod(Collection<MyType> param) {// Advice implementation
}

为了实现这一点,我们必须检查集合的每个元素,这是不合理的,因为我们也无法决定如何处理null值。要实现类似的效果,您必须将参数键入Collection<?>并手动检查元件的类型。

确定参数名称

通知调用中的参数绑定依赖于将切入点表达式中使用的名称与建议和切入点方法签名中声明的参数名称相匹配。

本节交替使用argumentparameter 这两个术语,因为AspectJ API将parameter names 称之为 argument names。

Spring AOP使用以下ParameterNameDiscoverer实现来确定参数名称。每个发现者都将有机会发现参数名称,第一个成功的发现者获胜。如果没有一个注册的发现者能够确定参数名称,则将引发异常。

AspectJAnnotationParameterNameDiscoverer

使用用户通过相应建议或切入点注释中的argNames属性显式指定的参数名称。有关详细信息,请参见显式参数名称。

KotlinReflectionParameterNameDiscoverer

使用Kotlin反射API来确定参数名称。只有当类路径上存在此类API时,才使用此发现程序。

StandardReflectionParameterNameDiscoverer

使用标准的java.lang.reflect.Parameter API来确定参数名称。要求使用javac的-parameters标志编译代码。Java 8+上的推荐方法。

AspectJAdviceParameterNameDiscoverer

从切入点表达式、返回子句和抛出子句中推导参数名称。有关所使用算法的详细信息,请参阅javadoc。

显式指定参数名称

@AspectJ建议和切入点注释有一个可选的argNames属性,您可以使用它来指定注释方法的参数名称。

如果@AspectJ方面是由AspectJ编译器(ajc)编译的,即使没有调试信息,也不需要添加argNames属性,因为编译器保留了所需的信息。

类似地,如果使用-parameters标志使用javac编译了@AspectJ方面,则不需要添加argNames属性,因为编译器保留了所需的信息。

  • 以下示例显示了如何使用该argNames属性:

java

@Before(value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",//1argNames="bean,auditable")//2
public void audit(Object bean, Auditable auditable)  {                                                                                                                                   ble) {AuditCode code = auditable.value();// ... use code and bean
}

1、引用组合切入点表达式中定义的名为切入点的publicMethod。

2、声明bean和auditable作为参数名称。

如果第一个参数的类型为JoinPoint、ProceedingJoinPoint或JoinPoint.StaticPart,您可以从argNames属性的值中省略参数的名称。例如,如果修改前面的建议以接收连接点对象,则argNames属性不需要包括它:

java

@Before(value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)", //1argNames="bean,auditable")//2
public void audit(JoinPoint jp, Object bean, Auditable auditable) {AuditCode code = auditable.value();// ... use code, bean, and jp
}

1、引用组合切入点表达式中定义的名为切入点的publicMethod。

2、声明bean和auditable作为参数名称。

对JoinPoint、ProceedingJoinPoint或JoinPoint类型的第一个参数进行的特殊处理。StaticPart对于不收集任何其他连接点上下文的建议方法特别方便。在这种情况下,可以省略argNames属性。例如,以下建议不需要声明argNames属性:

java

@Before("com.xyz.lib.Pointcuts.anyPublicMethod()")//1
public void audit(JoinPoint jp) {// ... use jp
}

1、引用组合切入点表达式中定义的名为切入点的publicMethod。

参数处理

我们之前说过,我们将描述如何使用在Spring AOP和AspectJ中一致工作的参数编写一个继续调用。解决方案是确保通知签名按顺序绑定每个方法参数。以下示例显示了如何执行此操作:

@Around("execution(List<Account> find*(..)) && " +"com.xyz.CommonPointcuts.inDataAccessLayer() && " +"args(accountHolderNamePattern)") //1
public Object preProcessQueryPattern(ProceedingJoinPoint pjp,String accountHolderNamePattern) throws Throwable {String newPattern = preProcess(accountHolderNamePattern);return pjp.proceed(new Object[] {newPattern});
}

1、引用共享命名切入点定义中定义的inDataAccessLayer命名切入点。

在许多情况下,无论如何都要执行此绑定(如前面的示例所示)。

切面顺序

当多条建议都想在同一个连接点运行时会发生什么?Spring AOP 遵循与 AspectJ 相同的优先级规则来确定通知执行的顺序。最高优先级的建议首先“在进入的路上”运行(因此,给定两条之前的建议,优先级最高的一条首先运行)。从连接点“退出”时,优先级最高的通知最后运行(因此,给定两条后通知,具有最高优先级的一条将运行第二个)。

当在不同方面定义的两条通知都需要在同一个连接点运行时,除非您另外指定,否则执行顺序是未定义的。您可以通过指定优先级来控制执行顺序。这是通过在org.springframework.core.Ordered方面类中实现接口或使用注释对其进行@Order注释以正常的 Spring 方式完成的。给定两个方面,从Ordered.getOrder()(或注释值)返回较低值的方面具有较高的优先级。

特定方面的每个不同建议类型在概念上都意味着直接应用于连接点。因此,@AfterThrowing建议方法不应该从附带的@After/@AfterReturning方法接收异常。

从Spring Framework 5.2.7开始,需要在同一连接点运行的同一@Aspect类中定义的建议方法根据其建议类型按以下顺序分配优先级,从最高到最低:

@Around、

@Before、

@After、

@AfterReturning

@AfterThrough。

然而,请注意,@After建议方法将在同一方面的任何@AfterReturning或@AfterThrough建议方法之后有效地调用,遵循AspectJ对@After的“After-finally建议”语义。

当在同一个@Aspect类中定义的两个相同类型的建议(例如,两个@After建议方法)都需要在同一连接点运行时,排序是未定义的(因为无法通过反射javac编译类来检索源代码声明顺序)。考虑将这些建议方法折叠为每个@Aspect类中每个连接点的一个建议方法,或者将这些建议重构为单独的@Aspect类别,您可以通过Ordered或@order在方面级别进行排序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/196137.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL基础『数据类型』

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; MySQL 学习 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 &#x1f381;软件版本&#xff1a; MySQL 5.7.44 文章目录 1.数据类型一览2.整型2.1.INT2.2.BIT 3.浮点数3.1.FLOAT3.2.DECIMAL3…

Spring Cache快速入门教程及案例

1. Spring Cache介绍 Spring Cache提供了一组注解&#xff0c;使开发者能够轻松地在方法上定义缓存行为 Spring Cache抽象了缓存的底层实现&#xff0c;允许开发者选择使用不同的缓存提供者&#xff08;如 Ehcache、Redis、Caffeine 等&#xff09;。通过配置相应的缓存管理器…

java读取微信p12证书信息

import java.security.*; import java.security.cert.X509Certificate; public class TestController { /*** 获取私钥*/public static void main(String args[]) throws Exception {String mchId "商户号";KeyStore ks KeyStore.getInstance("PKCS12");…

倚天屠龙:Github Copilot vs Cursor

武林至尊&#xff0c;宝刀屠龙。号令天下&#xff0c;莫敢不从。倚天不出&#xff0c;谁与争锋&#xff01; 作为开发人员吃饭的家伙&#xff0c;一款好的开发工具对开发人员的帮助是无法估量的。还记得在学校读书的时候&#xff0c;当时流行CS架构的RAD&#xff0c;Delphi和V…

香港虚拟信用卡如何办理,支持香港apple id

什么是虚拟信用卡&#xff1f; 虚拟信用卡&#xff0c;英文称之为Virtual Credit Card Numbers&#xff0c;就是指没有实体卡片&#xff0c;是基于银行卡上面的BIN码所生成的虚拟账号。通常用于进行网络交易&#xff0c;使用起来很方便&#xff0c;也很安全。 它与实体信用卡…

虚函数不能声明为static

虚函数申明为static报错 class Foo { public:Foo()default;static virtual ~Foo(){} };int main() {Foo foo;return 0; };main.cpp:10:25: error: member ‘~Foo’ cannot be declared both virtual and static static virtual ~Foo() 代码编译会报错&#xff0c;不允许同时声…

vue之mixin混入

vue之mixin混入 mixin是什么&#xff1f; 官方的解释&#xff1a; 混入 (mixin) 提供了一种非常灵活的方式&#xff0c;来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时&#xff0c;所有混入对象的选项将被“混合”进入该组件本身的…

热门文章采集器【2023】

自媒体成为了许多人追逐的梦想&#xff0c;而爆文则是迈向成功的关键一步。随着越来越多的内容涌现&#xff0c;如何找到独特而引人注目的素材成为了自媒体创作者们面临的难题。本文将深入讲解当下热门的文章采集器&#xff0c;分享使用过的工具经验。 1.文章采集器的作用&…

DevOps搭建(三)-Git安装详细步骤

前面两篇文章我们讲了如何安装swappiness安装和虚拟机。这篇我们详细讲下如何安装Git。 1、YUM源更改为阿里云镜像源 1.1、备份CentOS-Base.repo 先备份原有的 CentOS-Base.repo 文件 sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup…

RAR解压软件|怎么解压文件?|软件教学

咱说正事&#xff0c;之前不是给大家推荐了几个解压软件吗。 但是发现很多小伙伴下载了不会用&#xff0c;所以&#xff01;我来了&#xff01; 之前推荐的解压精灵&#xff0c;真的超级方便&#xff01;我们一般打开压缩文件需要先解压才能查看&#xff0c;很多人都是把文件传…

YOLOv8最新结构改进:首发最新改进,极简高效,UniRepLKNet作为改进升级版RepLKNet(博客内附源代码),适用于图像识别,即插即用打破性能瓶颈

💡本篇内容:YOLOv8最新结构改进:首发最新改进,极简高效,RepLKNet改进升级版UniRepLKNet(博客内附源代码),适用于图像识别,即插即用打破性能瓶颈 💡🚀🚀🚀本博客 改进源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 💡本文提出改进 原创 方式:二…

C 中的指针 - 数组和字符串

0. 为什么是指针和数组&#xff1f; 在C语言中&#xff0c;指针和数组有着非常密切的关系。应该将它们放在一起讨论的原因是&#xff0c;使用数组表示法 ( arrayName[index]) 可以实现的功能也可以使用指针实现&#xff0c;通常速度更快。 1. 一维数组 让我们看看当我们写的…

简谈PostgreSQL的wal_level=logic

一、PostgreSQL的wal_levellogic的简介 wal_levellogic 是 PostgreSQL 中的一个配置选项&#xff0c;用于启用逻辑复制&#xff08;logical replication&#xff09;功能。逻辑复制是一种高级的数据复制技术&#xff0c;它允许您将变更&#xff08;例如插入、更新和删除&#…

Linux系统中进程间通信(Inter-Process Communication, IPC)

文章目录 进程间通信介绍进程间通信目的进程间通信发展 管道什么是管道 匿名管道用fork来共享管道原理站在文件描述符角度-深度理解管道站在内核角度-管道本质管道读写规则管道特点 命名管道创建一个命名管道匿名管道与命名管道的区别命名管道的打开规则 命名管道的删除用命名管…

Shopify二次开发之三:liquid语法学习(访问Objects和Schema数据模型)

目录 Objects &#xff08;对象&#xff09; 全局对象 all_products&#xff1a;商店中所有的商品 articles: 商店中的所有文章 collections&#xff1a;商店中所有的集合 模板对象 在product.json&#xff08;配置的section中) 访问product对象 在collection.json中可…

40. 组合总和 II

题目描述 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 **注意&#xff1a;**解集不能包含重复的组合。 示例 1: 输入: candidates…

Android之 知识总结第二篇

一&#xff0c; Gradle 、AGP(Android Gradle Plugin)、 buildTools分别是什么&#xff0c;他们之间什么关系&#xff1f; Gradle Gradle是基于JVM的构建工具。他本身使用jave写的&#xff0c;gradle的脚本也就是build.gradle通常是用groovy语言。Android BuildTools Android S…

1D和2D布朗运动matlab

布朗运动是一种随机现象&#xff0c;下面的M函数brwnm2.m给出了二维Brown运动&#xff0c;其中[t0,tf]是时间区间&#xff0c;h是采样步长&#xff0c;w(t)&#xff0c;z(t)是布朗运动。function [t,w,z]brwnm2(t0,tf,h) tt0:h:tf; xrandn(size(t))*sqrt(h); yrandn(size(t))*s…

LightDB - 支持quarter 函数[mysql兼容]

LightDB 从23.4版本开始支持 quarter 函数。 简介 quarter 函数用来确定日期对应的季度&#xff0c; 如 ‘20231204’ 对应12月&#xff0c;也就是第四季度。 下面为mysql8.0中描述 Returns the quarter of the year for date, in the range 1 to 4, or NULL if date is NUL…

二叉树题目:二叉树的完全性检验

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;二叉树的完全性检验 出处&#xff1a;958. 二叉树的完全性检验 难度 5 级 题目描述 要求 给定一个二叉树的根结点 root \texttt{root} root&…