在GUI框架中,显式跟踪父/子关系是很常见的 - 给定一个任意的GUI组件,可以在"拥有"它的组件的层次结构中向上导航。
父组件不一定是实际创建其子组件的实体,这些关系通常在创建后配置。
我有一种情况,我感兴趣的是创建关系,即一个对象创建了另一个对象。
所涉及的对象属于不同的类,它们之间通常没有继承关系或类似关系。
实际上,我创建了具有 id 的"主"对象,并且我希望由这些对象创建的所有对象(直接或以 n 度分离)知道其特定"主"对象的 id。
[ ID 实际上仅用于日志记录目的。
我可以想象这样的事情:
public class Master
{
@GroupId
private final long id;
}
@InheritGroupId
public class Foo
{
public void bar()
{
logger.info("I belong to group {}", XXX);
}
}
对于 Master 对象,id 将在其构造函数中设置。任何标有 @InheritGroupId 的类都会在构造时以某种方式查找堆栈并查找第一个调用者对象,该对象要么通过 @GroupId 注释直接知道其组 id,要么以与该类相同的方式确定它,即也用 @InheritGroupId 标记的类。
然后您将如何访问 group-id 值我不确定,在上面的代码中,我刚刚在我想访问它的地方使用了 XXX。
我说"以某种方式查找堆栈",但据我所知,不可能在直接 Java 中像这样检查堆栈。
也许不需要烟囱检查的替代结构是可能的。或者也许某种AOP字节编织方法是可能的?
目前,我将 groupId 作为显式构造函数参数传递给系统中的几乎每个对象。对我来说,所有对象都必须维护一个成员变量,该变量实际上不是其逻辑的一部分,而是纯粹用于日志记录,这对我来说似乎是一种耻辱。
显式传递 groupId 确实具有明确指出以下情况的优势:在低级和我的"主"对象之一之间建立创建者关系是困难的。
如果你有任何想法如何处理我所描述的注释或字节码编织,或者你认为明确传递组ID实际上是最好的方法,或者你对如何实现同样的事情有一些完全不同的想法,那么请告诉我。
/乔治
更新:请注意,给定主对象的所有"子"对象并不是在一个给定的时间点预先创建的,即这不是简单地将 group-id 设置为某个单例,然后让子对象在集体创建时以某种方式访问此单例的问题。
我认为您想要每个控制流方面。每次在切入点中输入方法时,都会创建该方面的一个实例。每次退出控制流时,它都会变为未引用状态。它本质上是线程本地的,它将在您想要初始化它时创建。这只是一个草图,但我想你会想要这样的东西:
aspect GetId percflow(callsFromMaster()) {
private long id;
pointcut callsFromMaster() : within(Master.*);
pointcut childConstructors() : cflow(callsFromMaster()) && execution(Foo.new.(..));
before(Master master) : callsFromMaster() && this(master) {
this.id = master.getId();
}
after(Foo child) : childConstructors() && this(child) {
child.id = this.id;
}
}
我会读作:每次从 Master 方法输入调用的控制流时,请创建这方面的新实例。在每次调用之前,请保存 ID。在同一控制流中,每次创建新 Foo 时,都将 ID 从当前主节点复制到新 Foo。