gpt4 book ai didi

java - AspectJ 使用 around 建议和 ProceedingJoinPoint 时遇到问题

转载 作者:行者123 更新时间:2023-12-02 10:33:59 24 4
gpt4 key购买 nike

我是 AOP 新手,我需要在我的项目中使用 AspectJ。我需要使用周围建议,但使用它时遇到问题,我的 .aj 类中有以下代码,

pointcut checkUser(ProceedingJoinPoint jp,User user): call(* com.example.UserAccount.MyUI.checkUser(..))&& args(jp,user);

void around(ProceedingJoinPoint jp,User user) throws Throwable : checkUser(jp,user){
// Condition checks one of the user boolean property
if(condition){
jp.proceed();
}else{
// Do nothing
}
}

但我总是收到此警告,

advice defined in Aspects.UserAccount has not been applied [Xlint:adviceDidNotMatch]

顺便说一句,我在没有 ProceedingJoinPoint 的情况下尝试了它,只尝试了 proceed(); 但随后收到此警告,参数太少,无法继续,预期为 1

我很感谢您的任何帮助或提示!

雷扎

最佳答案

首先,我建议阅读 AspectJ 文档以学习语法。当您使用 native AspectJ 语法时,这就像学习一种新的编程语言或至少是一种 Java 扩展。您正在做的是将 native 语法与基于注释的语法混合在一起。尝试坚持其中一个。我确信您在任何教程中都没有找到这一点,但最终通过反复试验得到了该语法。

您不需要以 native 语法绑定(bind)连接点参数,因为它是隐式自动存在的。自动绑定(bind)的连接点始终命名为 thisJoinPoint,所有教程都向您展示了这一点。仅在基于注释的语法中,您需要绑定(bind)连接点并可以根据需要对其进行命名,但即便如此,我还是建议坚持使用 thisJoinPoint 因为这样从注释重构为原生语法会更容易,而且您的眼睛会更容易理解。用于在方面代码中发现该变量名称。

您收到的警告意味着您定义的切入点与代码的任何部分都不匹配,至少与方面编织器或编译器可见的任何部分都不匹配。发生这种情况的原因可能有很多,例如包或类名拼写错误,建议返回类型错误(对于非 void 方法,返回类型必须是 Object 或更具体地匹配您想要拦截的方法返回的内容)。假设例如checkUser(..) 返回一个 boolean,周围建议应该做同样的事情。我使用你的包和类名编写了一个示例。此外,包名称应该是小写的,但我使用了你的,假设它们确实是包名称而不是内部类:

帮助类:

package com.example.UserAccount;

public class User {
private String name;

public User(String name) {
this.name = name;
}

public String getName() {
return name;
}

@Override
public String toString() {
return "User(" + name + ")";
}
}

按方面定位的类 + 示例主要方法:

package com.example.UserAccount;

public class MyUI {
public boolean checkUser(User user) {
return user.getName().toUpperCase().contains("ADMIN");
}

public static void main(String[] args) {
MyUI ui = new MyUI();
System.out.println(ui.checkUser(new User("Administrator")));
System.out.println(ui.checkUser(new User("john")));
System.out.println(ui.checkUser(new User("xander")));
System.out.println(ui.checkUser(new User("admiral")));
System.out.println(ui.checkUser(new User("SySaDmiN")));
}
}

如您所见,由于我为 checkUser(..)< 编写的检查逻辑,我们预计第一个和最后一个条目的输出为“true”,而中间条目的输出为“false”/.

现在让我们编写一个方面,它也为名为“Xander”的用户返回“true”,例如为了给他管理权限或其他什么。我正在弥补这一点,因为您没有提供 MCVE正如您在 StackOverflow 上总是应该做的那样,但只是一个不连贯的代码片段,让每个人都试图回答您的问题,猜测您到底想要实现什么以及如何重现您的问题。

方面:

package Aspects;

import com.example.UserAccount.User;
import com.example.UserAccount.MyUI;

public aspect UserAccount {
pointcut checkUser(User user) :
execution(boolean MyUI.checkUser(*)) && args(user);

boolean around(User user) : checkUser(user) {
System.out.println(thisJoinPoint + " -> " + user);
if (user.getName().equalsIgnoreCase("xander"))
return true;
return proceed(user);
}
}

我刚刚导入了 MyUI 类,因此无需在此处使用完全限定的类名。同样,这是 native 语法的优点,在基于注释的语法中,您必须使用完全限定名称。

我还用更明确的 boolean MyUI.checkUser(*) 替换了通用的 * MyUI.checkUser(..) (这也可以工作),因为我们已经知道该方法返回一个 boolean 值并且只有一个参数,无论如何,我们都通过从周围建议返回一个 boolean 值并通过 args() 绑定(bind)一个参数来假设这一点。您还可以更具体并使用 boolean MyUI.checkUser(User)

此外,我使用 execution() 而不是 call() 因为它更高效,因为它将建议代码一​​次编织到执行方法中,而不是主方法中每个方法调用五次。如果 MyUI 类超出 AspectJ 编织器/编译器的范围,即因为它不在使用 AspectJ Maven 编译的模块中,则只需使用 call() .

控制台日志:

execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(Administrator)
true
execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(john)
false
execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(xander)
true
execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(admiral)
false
execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(SySaDmiN)
true

瞧,这个方面起作用了。它使目标方法为用户“xander”返回“true”。

关于java - AspectJ 使用 around 建议和 ProceedingJoinPoint 时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53433710/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com