我想写一个与注释字段上的公共方法执行相匹配的切入点。这怎么可能不起作用。 get(@Important)按预期(单独)工作,但它当然会匹配对该字段的所有访问。我想将此限制为仅公共方法执行。
这有可能吗?我没有编译错误,但另一方面它似乎没有工作..
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() {
}
答案 0 :(得分:2)
对于你想要的东西,没有开箱即用的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
)。在我的示例代码的早期版本中,当我刚刚在一个简单的集合中记录“重要对象”时,我可以选择永远不会从集合中删除以前的“重要对象”,即使它们不再被引用或者总是删除它们如果第二个推荐者仍指向“重要对象”。地图方法使我能够为每个“重要对象”记录多个引用。
如果您运行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
这样的原始类型,理论上可以多次作为“重要对象”出现会发生什么,因为几个不相关的重要成员创建了相同的对象。我还没有测试过有关自动(联合)拳击的事情,请自己尝试。但是,如果您控制边界条件和用例,您可以做出明智的决定并按原样使用代码或其变体,以实现您的需求。代码可能有改进的潜力,我只是很好奇,想要破解概念证明。
答案 1 :(得分:0)
您想要使用withinCode
切入点,如下所示:
@Pointcut(value = "get(@Important * *) && withinCode(public * *(..))")
void testPointCut() {
}