【译】AOP- Advice Param And Order

2023-12-04 17:20
文章标签 order aop advice param

本文主要是介绍【译】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在方面级别进行排序。

这篇关于【译】AOP- Advice Param And Order的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/454274

相关文章

SSM项目使用AOP技术进行日志记录

本步骤只记录完成切面所需的必要代码 本人开发中遇到的问题: 切面一直切不进去,最后发现需要在springMVC的核心配置文件中中开启注解驱动才可以,只在spring的核心配置文件中开启是不会在web项目中生效的。 之后按照下面的代码进行配置,然后前端在访问controller层中的路径时即可观察到日志已经被正常记录到数据库,代码中有部分注释,看不懂的可以参照注释。接下来进入正题 1、导入m

SpringBoot中利用EasyExcel+aop实现一个通用Excel导出功能

一、结果展示 主要功能:可以根据前端传递的参数,导出指定列、指定行 1.1 案例一 前端页面 传递参数 {"excelName": "导出用户信息1725738666946","sheetName": "导出用户信息","fieldList": [{"fieldName": "userId","fieldDesc": "用户id"},{"fieldName": "age","fieldDe

Spring6详细学习笔记(IOC+AOP)

一、Spring系统架构介绍 1.1、定义 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。Spring官网 Spring是一款主流的Java EE 轻量级开源框架,目的是用于简化Java企业级引用的开发难度和开发周期。从简单性、可测试性和松耦合度的角度而言,任何Java应用都可以从Spring中受益。Spring框架提供自己提供功能外,还提供整合其他技术和框架

AOP之执行前通知@Before

Spring AOP之执行前通知@Before 此文章说一下执行前通知,即注解@Before。 作用 多用于日志记录、权限校验、初始化资源等。 触发时间 目标函数执行触发。 定义 public class AopBeforeAspect {@Before("execution(public * com.example.demo.service.impl.AccountServiceI

MapReduce算法 – 反转排序(Order Inversion)

译者注:在刚开始翻译的时候,我将Order Inversion按照字面意思翻译成“反序”或者“倒序”,但是翻译完整篇文章之后,我感觉到,将Order Inversion翻译成反序模式是不恰当的,根据本文的内容,很显然,Inversion并非是将顺序倒排的意思,而是如同Spring的IOC一样,表明的是一种控制权的反转。Spring将对象的实例化责任从业务代码反转给了框架,而在本文的模式中,在map

兔子-(PHP 5.3 and above) Please set 'request_order' ini value to include C,G and P (recommended: 'CGP'

由于在PHP最新的版本中增加了一个配置项目“request_order”,默认值为“GP”,这个存在一定的安全风险。这里我们建议用户将配置更改为“CGP” 可以在php的安装目录下找到php.ini配置目录,找到下面选项: request_order = "GP"  更改为 request_order = "CGP"   重启服务器后即可。 此

Spring之AOP面向切面编程实现(一)

实现方式:基于配置XML和基于注解实现。 场景:一个手机进货系统,一旦要进货(或出货),要提前记录进货时间,进货完毕后,还要提醒其它人进行验货。 分析:3步走,1,操作进货(或出货)的方法的时候,先记录当前的时间,完毕后,提醒其他人验货。为了不使代码变得冗余,采用aop的策略实现。 基于配置实现 进货出货的接口: IPhoneService.java public i

Hive中order by,sort by,distribute by,cluster by的区别

一:order by order by会对输入做全局排序,因此只有一个Reducer(多个Reducer无法保证全局有序),然而只有一个Reducer,会导致当输入规模较大时,消耗较长的计算时间。关于order by的详细介绍请参考这篇文章:Hive Order by操作。 二:sort by sort by不是全局排序,其在数据进入reducer前完成排序,因此,如果用sort

MySQL - 关于 Order By 乱序问题

一、问题     在 Order By 的查询语句中, 如果 Order By 的字段存在较多相同数据时,可能会出现乱序的问题,即多次查询的返回结果顺序不一致 二、方案     添加第二个 Order By 的字段,且该字段尽量唯一 三、示例 -- 原始语句SELECT * FROM detail ORDER BY type ASC-- 调整语句SELECT * FROM detai

关于spring 类内部方法调用aop不生效原因,以及jdk,cglib 动态代理原理

目录 引入:spring的aop 深入实验(发现类内部方法调用的代理可以生效) 自己实现动态代理(cglib) spring的动态代理实现 自己实现spring aop的效果 关于上述自己实现aop与spring aop的区别 自己实现的aop:  spring 实现的aop: 模仿spring aop的效果, 代码示例: spring 什么时候为类创建代理 spring b