AspectJ在使用around advice和ProceedingJoinPoint时遇到问题



我是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();,但后来得到了这个警告,too few arguments to proceed, expected 1

我感谢任何一个帮助或提示!

Reza

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

您不需要以本机语法绑定joinpoint参数,因为它是隐式且自动存在的。自动绑定的连接点总是命名为thisJoinPoint,所有教程都会向您展示这一点。只有在基于注释的语法中,您才需要绑定连接点,并可以根据自己的意愿对其进行命名,但即使这样,我也建议您坚持使用thisJoinPoint,因为从注释到本机语法的重构更容易,而且您的眼睛已经习惯于在方面代码中发现变量名称。

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

助手类:

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",例如,为了给他管理权限或其他什么。我之所以编造这个,是因为你没有像往常一样在StackOverflow上提供MCVE,而是提供了一个不连贯的代码片段,让每个人都在猜测你到底想实现什么,以及如何重现你的问题。

方面:

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类,所以这里不需要使用完全限定的类名。同样,这是本机语法的优势,在基于注释的语法中,您必须使用完全限定的名称。

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

此外,我使用execution()而不是call(),因为它更高效,因为它只将建议代码编织到执行方法中一次,而不是为主方法中的每个方法调用编织五次。如果MyUI类在AspectJ weaver/编译器无法访问的情况下,即因为它不在使用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"。

相关内容

  • 没有找到相关文章

最新更新