我是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
答案 0 :(得分:1)
首先,我建议阅读AspectJ文档以学习语法。当您使用本机AspectJ语法时,这就像学习新的编程语言或至少是Java扩展一样。您正在做的是将本机语法与基于注释的语法混合使用。尝试坚持下去。我相信您在任何教程中都找不到,但是最终还是通过反复试验得出了该语法。
您不需要用本机语法绑定连接点参数,因为它隐式地自动存在。自动绑定的连接点始终被命名为thisJoinPoint
,因为所有教程都一定会告诉您。只有在基于注释的语法中,您才需要绑定连接点并可以根据需要命名它,但是即使如此,我仍然建议坚持使用thisJoinPoint
,因为这样从注释到本机语法的重构会更容易,并且您的眼睛习惯于发现您的方面代码中的变量名称。
所收到的警告意味着您定义的切入点与代码的任何部分都不匹配,至少与weaver或编译器可见的任何部分都不匹配。发生这种情况的原因可能很多,例如包或类名拼写错误,建议返回类型错误(非无效方法的返回类型必须为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”,例如为了给他管理员权限或其他。我之所以要这样做,是因为您没有像往常那样在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
类,因此这里不需要使用完全限定的类名。同样,这是本机语法的优势,在基于注释的语法中,您将必须使用完全限定的名称。
我还用更明确的* MyUI.checkUser(..)
代替了通用的boolean MyUI.checkUser(*)
(也可以使用),因为我们已经知道该方法返回一个布尔值并且只有一个参数,无论如何我们都假定这两个参数从周围的建议返回布尔值,并通过args()
绑定一个参数。您甚至可以更具体一些,并使用boolean MyUI.checkUser(User)
。
此外,我使用execution()
而不是call()
是因为它效率更高,因为它将建议代码仅编织到执行方法一次,而不是将main方法中的每个方法调用编织五次。仅当call()
类超出AspectJ编织者/编译器的范围时,才需要使用MyUI
,即,因为该类不在用AspectJ Maven编译的模块中。
控制台日志:
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”。