我想写一个与注释字段上的公共方法执行相匹配的切入点.这怎么可能不起作用.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);
}
}
Run Code Online (Sandbox Code Playgroud)
作品:
@Pointcut(value = "get(@Important * *)")
void testPointCut() {
}
Run Code Online (Sandbox Code Playgroud)
不起作用:
@Pointcut(value = "get(@Important * *) && execution(public * *(..))")
void testPointCut() {
}
Run Code Online (Sandbox Code Playgroud)
对于您想要的,没有开箱即用的 AspectJ 解决方案,因为如果您拦截任何对象的方法执行,则不会连接到可能指向这些对象的带注释字段。拦截带注释的类或带注释的方法的方法执行会更容易,但这不是您想要做的。
这是一个小代码示例,向您展示了一种解决方法,但也显示了其局限性:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Important {}
Run Code Online (Sandbox Code Playgroud)
public class Counter {
private int count = 0;
public void add(int value) {
count = count + value;
}
@Override
public String toString() {
return super.toString() + "[count=" + count + "]";
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
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); }
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我的方面保留了一组“重要对象”。更准确地说,它的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]
Run Code Online (Sandbox Code Playgroud)
请仔细将代码与main日志输出进行比较,以了解我测试了哪些常规情况和特殊情况。
正如我所说,该方法有其局限性:
intor are这样的基本类型String,理论上可以作为“重要对象”多次出现,因为几个不相关的重要成员创建相同的对象,会发生什么。我也没有测试过自动(取消)装箱会发生什么,请自行尝试。但是,如果您可以控制边界条件和用例,则可以做出明智的决定并按原样使用代码或其变体来实现您的需求。该代码可能有改进的潜力,我只是好奇并想破解概念证明。
| 归档时间: |
|
| 查看次数: |
3651 次 |
| 最近记录: |