gpt4 book ai didi

java - 带有AspectJ的库:切入点捕获使用它的应用程序中的行为

转载 作者:行者123 更新时间:2023-12-01 10:14:44 28 4
gpt4 key购买 nike

所以这是我正在研究的疯狂想法。仍然不能完全确定它是否会起作用。

我正在开发用于程序抽象的工具。为此,我希望能够在实例化某些类时检测并记录WeakReference。这些类将不在我的库中,而将在使用我的库的应用程序中。我这样做是为了可以在特定时间反射地调用其中的方法。

该应用程序中的类将具有特殊的注释,以将它们标记为我要存储其引用的实例化的类。因此,我不需要在所有班级附近的任何地方(只有特定班级)这样做。

我的问题有两个:

1)如果切入点位于作为项目依赖项的jar中,AspectJ是否可以指向该项目中的类?

2)为带有注释的类的构造函数创建切入点的最佳方法是什么?

最佳答案

如果即使您的库是依赖项,也无法通过以-javaagent:/path/to/aspectjweaver.jar开头的应用程序依赖于应有的使用库,那么该库具有哪些类型的用户?在我看来,您似乎想修改其用户或构建者不知道的应用程序的控制流。我称这样的图书馆为特洛伊木马。无论如何,关于您的问题:


如果您不能依靠记住使用Java代理方法(LTW,加载时编织)的用户,请告诉他们使用AspectJ Maven插件构建应用程序并使用编译时编织。这非常易于使用,并且在运行时仅需要依赖Aspectjrt.jar(AspectJ运行时),这从他们的角度来看只是一个普通的库。
使用LTW,即使 不是作为Java代理启动的,新版本的 AspectJ since 1.8.7也可以动态地启动加载时编织程序(如果它位于类路径上)。 (我知道,因为我自己实现了这个小功能。)请阅读说明,并意识到主要的缺点:它仅适用于在您的库附加了weaver之后加载的类,因此如果作为“黑客工具”使用,它是不可靠的您想加入其他人的课程。


我认为您的问题并不是真正的问题。技术不是这里的瓶颈,与用户的沟通才是瓶颈。写一个好的文档,并将LTW问题放在常见问题列表的顶部。



更新:

您问过如何编写一个方面来拦截构造函数调用,因此,我假设您要保留对实例化(新创建)对象的弱引用,只要它们存在且不被垃圾收集器回收即可。

但是首先要注意-我们需要一个注释:

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface CatchMe {}


请注意 @Inherited。这意味着,如果对一个类进行了注释,则其所有子类都将继承该注释。根据 JDK documentation的说法,这不适用于带注释的接口,也就是说,类不会从已实现的接口继承任何注释,正如我们稍后会看到的。

更新:因为我之前已经多次回答过有关注释继承的问题,所以我刚刚记录了该问题以及 Emulate annotation inheritance for interfaces and methods with AspectJ中的解决方法。

现在我们需要一些示例类:

package de.scrum_master.app;

@CatchMe
public class AnnotatedBase {
public void doSomething() {
System.out.println("Doing something");
}
}


package de.scrum_master.app;

public class Sub extends AnnotatedBase {
public void doSomethingElse() {
System.out.println("Doing something else");
}
}


如您所见, Sub扩展了 AnnotatedBase并应继承其 @CatchMe批注。

这是带有带注释的接口和实现类的反示例,该类不应继承注释,因此不会被我们的方面捕获:

package de.scrum_master.app;

@CatchMe
public interface Greeter {
void sayHelloTo(String someone);
}


package de.scrum_master.app;

public class Other implements Greeter {
@Override
public void sayHelloTo(String someone) {
System.out.println("Hello " + someone + "!");
}
}


为了测试我们尚未编写的方面,我们需要一个小的驱动程序应用程序来实例化一些对象:

package de.scrum_master.app;

public class Application {
public static void main(String[] args) {
new AnnotatedBase().doSomething();
new Sub().doSomething();
System.gc();
System.out.println("\n----- GC -----\n");
new Sub().doSomethingElse();
new Other().sayHelloTo("world");
}
}


请注意,应用程序在某一时刻执行垃圾回收。这样,我们可以看到将在接下来的方面中使用的 WeakHashMap会发生什么。

没有任何方面的控制台日志如下所示:

Doing something
Doing something

----- GC -----

Doing something else
Hello world!


最后但并非最不重要的,这是我们的方面。它使创建对象的弱哈希图保持活动状态(即不受GC影响),指向它们各自的类,这样我们就可以针对该方面的对象实例和受影响的类创建报告。

package de.scrum_master.aspect;

import java.util.WeakHashMap;

import de.scrum_master.app.CatchMe;

public aspect AnnotatedConstructorInterceptor {
private WeakHashMap<Object, Class<?>> livingObjects = new WeakHashMap<>();

after(Object newObject) : execution((@CatchMe *).new(..)) && target(newObject) {
System.out.println(thisJoinPoint);
livingObjects.put(newObject, newObject.getClass());
printReport();
}

private void printReport() {
System.out.println(" Living objects:");
for (Object livingObject : livingObjects.keySet())
System.out.println(" " + livingObject);
System.out.println(" Affected classes:");
for (Class<?> clazz : livingObjects.values())
System.out.println(" " + clazz.getName());
System.out.println();
}
}


有了方面之后,日志输出将逐步:

1.) new AnnotatedBase().doSomething();

execution(de.scrum_master.app.AnnotatedBase())
Living objects:
de.scrum_master.app.AnnotatedBase@452b3a41
Affected classes:
de.scrum_master.app.AnnotatedBase

Doing something


2.) new Sub().doSomething();:您可以看到子类和基类构造函数是如何执行的,但是仅创建了一个对象并将其添加到哈希映射中。

execution(de.scrum_master.app.AnnotatedBase())
Living objects:
de.scrum_master.app.Sub@4a574795
de.scrum_master.app.AnnotatedBase@452b3a41
Affected classes:
de.scrum_master.app.Sub
de.scrum_master.app.AnnotatedBase

execution(de.scrum_master.app.Sub())
Living objects:
de.scrum_master.app.Sub@4a574795
de.scrum_master.app.AnnotatedBase@452b3a41
Affected classes:
de.scrum_master.app.Sub
de.scrum_master.app.AnnotatedBase

Doing something


3.) System.gc();:执行垃圾收集。此后,弱哈希图应再次为空。

----- GC -----


4.) new Sub().doSomethingElse();:现在,在GC成为弱哈希图中的唯一对象之后,再次实例化了一个子类对象。

execution(de.scrum_master.app.AnnotatedBase())
Living objects:
de.scrum_master.app.Sub@f6f4d33
Affected classes:
de.scrum_master.app.Sub

execution(de.scrum_master.app.Sub())
Living objects:
de.scrum_master.app.Sub@f6f4d33
Affected classes:
de.scrum_master.app.Sub

Doing something else


5.) new Other().sayHelloTo("world");:这应该不会影响弱哈希图,因为如上所述,由于从接口类到实现类的注释的非继承性,因此未触发方面,因此未触发方面。

Hello world!


等等! :-)

关于java - 带有AspectJ的库:切入点捕获使用它的应用程序中的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35966080/

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