gpt4 book ai didi

java - 用于匹配注释字段上的公共(public)方法调用的 Aspectj 切入点

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:56:02 26 4
gpt4 key购买 nike

我想编写一个切入点来匹配在带注释的字段上执行公共(public)方法。这似乎永远行不通。 get(@Important) 按您的预期工作(独立),但它当然会匹配对该字段的所有访问。我想将其限制为仅执行公共(public)方法。

这可能吗?我没有收到编译错误,但另一方面它似乎不起作用..


public class Counter {
private int count = 0;

public void add(int value) {
count = count + value;
}
}

public class Visitors {
@Important
Counter counter = new Counter()

public void increaseCounter() {
counter.add(1);
}
}

作品:

@Pointcut(value = "get(@Important * *)")
void testPointCut() {
}

不起作用:

@Pointcut(value = "get(@Important * *) && execution(public * *(..))")
void testPointCut() {
}

最佳答案

对于您想要的,没有开箱即用的 AspectJ 解决方案,因为如果您拦截任何对象的方法执行,则没有与可能指向这些对象的注释字段的连接。拦截注释类或注释方法的方法执行会更容易,但这不是您想要做的。

这里是一个小代码示例,向您展示了一种解决方法,但也说明了它的局限性:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Important {}
public class Counter {
private int count = 0;

public void add(int value) {
count = count + value;
}

@Override
public String toString() {
return super.toString() + "[count=" + count + "]";
}
}
public class Visitors {
@Important
Counter counter = new Counter();

public void increaseCounter() {
counter.add(1);
}

public static void main(String[] args) {
Visitors visitors = new Visitors();
visitors.increaseCounter();
visitors.counter.add(3);
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("--------------------");

Counter unimportantCounter = new Counter();
unimportantCounter.add(11);
unimportantCounter.add(22);
System.out.println("unimportantCounter = " + unimportantCounter);
System.out.println("--------------------");

unimportantCounter = visitors.counter;
unimportantCounter.add(5);
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("unimportantCounter = " + unimportantCounter);
System.out.println("--------------------");

visitors.counter = new Counter();
visitors.increaseCounter();
visitors.counter.add(3);
unimportantCounter.add(100);
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("unimportantCounter = " + unimportantCounter);
System.out.println("--------------------");

Visitors otherVisitors = new Visitors();
otherVisitors.increaseCounter();
otherVisitors.counter.add(50);
System.out.println("otherVisitors.counter = " + otherVisitors.counter);
System.out.println("--------------------");

otherVisitors.counter = visitors.counter;
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("otherVisitors.counter = " + otherVisitors.counter);
System.out.println("--------------------");

otherVisitors.counter = new Counter();
visitors.increaseCounter();
otherVisitors.increaseCounter();
System.out.println("visitors.counter = " + visitors.counter);
System.out.println("otherVisitors.counter = " + otherVisitors.counter);
}
}
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.aspectj.lang.Signature;
import org.aspectj.lang.SoftException;

public aspect ImportantMethodInterceptor {
Map<Object, Set<Object>> importantObjects = new HashMap<Object, Set<Object>>();

pointcut importantSetter(Object newValue, Object target) :
set(@Important * *) && args(newValue) && target(target);
pointcut unimportantSetter(Object newValue, Object target) :
!set(@Important * *) && set(* *) && !withincode(*.new(..)) && args(newValue) && target(target);
pointcut publicMethod(Object target) :
execution(public * *(..)) && target(target) && !execution(public String *..toString());

before(Object newValue, Object target) : importantSetter(newValue, target) {
Object oldValue = getFieldValue(thisJoinPoint.getSignature(), target);
System.out.println("Important object for target " + target + ": " + oldValue + " -> " + newValue);
synchronized (importantObjects) {
Set<Object> referrers;
if (oldValue != null) {
referrers = importantObjects.get(oldValue);
if (referrers != null) {
referrers.remove(target);
if (referrers.size() == 0)
importantObjects.remove(oldValue);
}
}
if (newValue != null) {
referrers = importantObjects.get(newValue);
if (referrers == null) {
referrers = new HashSet<Object>();
importantObjects.put(newValue, referrers);
}
referrers.add(target);
}
}
}

// before(Object newValue, Object target) : unimportantSetter(newValue, target) {
// Object oldValue = getFieldValue(thisJoinPoint.getSignature(), target);
// System.out.println("Unimportant object for target " + target + ": " + oldValue + " -> " + newValue);
// }

before(Object target) : publicMethod(target) {
synchronized (importantObjects) {
if (importantObjects.get(target) != null)
System.out.println("Important method on " + target + ": " + thisJoinPointStaticPart);
else
System.out.println("Unimportant method on " + target + ": " + thisJoinPointStaticPart);
}
}

private Object getFieldValue(Signature signature, Object target) {
try {
Field field = signature.getDeclaringType().getDeclaredField(signature.getName());
field.setAccessible(true);
return field.get(target);
}
catch (Exception e) { throw new SoftException(e); }
}
}

如您所见,我的方面保留了一组“重要对象”。更准确地说,它是一个 Map,其中键是“重要对象”,值是引用集。这是必要的,因为理论上多个引荐来源网址(例如 Visitors 对象)可以指向相同的“重要对象”(例如特定的 Counter)。在我的示例代码的早期版本中,当我刚刚在一个简单的集合中记录“重要对象”时,我可以选择永远不从集合中删除以前的“重要对象”,即使它们不再被引用,或者即使它们不再被引用也总是删除它们如果第二个推荐人仍然指向“重要对象”。 map 方法使我能够为每个“重要对象”记录多个引荐来源网址。

如果您运行 Visitors.main(String[]),您将看到以下输出(请取消注释 before ... : unimportantSetter ... 建议,如果您希望看到更多日志输出):

Important object for target Visitors@1404536: null -> Counter@7fdcde[count=0]
Unimportant method on Visitors@1404536: execution(void Visitors.increaseCounter())
Important method on Counter@7fdcde[count=0]: execution(void Counter.add(int))
Important method on Counter@7fdcde[count=1]: execution(void Counter.add(int))
visitors.counter = Counter@7fdcde[count=4]
--------------------
Unimportant method on Counter@18ac738[count=0]: execution(void Counter.add(int))
Unimportant method on Counter@18ac738[count=11]: execution(void Counter.add(int))
unimportantCounter = Counter@18ac738[count=33]
--------------------
Important method on Counter@7fdcde[count=4]: execution(void Counter.add(int))
visitors.counter = Counter@7fdcde[count=9]
unimportantCounter = Counter@7fdcde[count=9]
--------------------
Important object for target Visitors@1404536: Counter@7fdcde[count=9] -> Counter@1d6096[count=0]
Unimportant method on Visitors@1404536: execution(void Visitors.increaseCounter())
Important method on Counter@1d6096[count=0]: execution(void Counter.add(int))
Important method on Counter@1d6096[count=1]: execution(void Counter.add(int))
Unimportant method on Counter@7fdcde[count=9]: execution(void Counter.add(int))
visitors.counter = Counter@1d6096[count=4]
unimportantCounter = Counter@7fdcde[count=109]
--------------------
Important object for target Visitors@b02e7a: null -> Counter@bb6ab6[count=0]
Unimportant method on Visitors@b02e7a: execution(void Visitors.increaseCounter())
Important method on Counter@bb6ab6[count=0]: execution(void Counter.add(int))
Important method on Counter@bb6ab6[count=1]: execution(void Counter.add(int))
otherVisitors.counter = Counter@bb6ab6[count=51]
--------------------
Important object for target Visitors@b02e7a: Counter@bb6ab6[count=51] -> Counter@1d6096[count=4]
visitors.counter = Counter@1d6096[count=4]
otherVisitors.counter = Counter@1d6096[count=4]
--------------------
Important object for target Visitors@b02e7a: Counter@1d6096[count=4] -> Counter@5afd29[count=0]
Unimportant method on Visitors@1404536: execution(void Visitors.increaseCounter())
Important method on Counter@1d6096[count=4]: execution(void Counter.add(int))
Unimportant method on Visitors@b02e7a: execution(void Visitors.increaseCounter())
Important method on Counter@5afd29[count=0]: execution(void Counter.add(int))
visitors.counter = Counter@1d6096[count=5]
otherVisitors.counter = Counter@5afd29[count=1]

请仔细比较 main 中的代码与日志输出,以查看我测试了哪些常规和特殊情况。

正如我所说,该方法有其局限性:

  • 我还没有测试如果重要字段具有原始类型(如 int)或 String 时会发生什么情况,理论上可以作为“重要对象”多次出现,因为几个不相关的important 成员创建相等的对象。我也没有测试自动(取消)装箱会发生什么,请自行尝试。
  • 方面代码有些复杂,而且速度可能不快。
  • 我不能保证可能没有其他我没有想到的问题。

但是,如果您可以控制边界条件和用例,则可以做出明智的决定并按原样使用代码或使用代码的变体来实现您的需求。该代码可能有改进的潜力,我只是好奇并且想破解一个概念证明。

关于java - 用于匹配注释字段上的公共(public)方法调用的 Aspectj 切入点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15138770/

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