5

我正在寻找一个使用 AspectJ 实现虫洞模式的示例(如果 Guice AOP 有能力实现这个,我会感兴趣)。

虫洞本质上允许您在调用流中传递其他参数,例如:

// say we have
class foo {
   public int m0 int a, int b) {
     return m1(a,b);
   }

   public int m1 int a, int b) {
     return m2(a,b);
   }

   public int m2 int a, int b) {
     return a+b;
   }
}
// and I wanted in a non-invasive manner to pass a third parameter of type
class context {
  String userName;
  long timeCalled;
  String path;
}
// I could use an advise to say print the context information
// to trace what was going on without mucking up my method signatures 

我相信这个 Ramnivas Laddad 在他的《AspectJ in Action》一书中就有这样的例子。

提前致谢。

4

3 回答 3

4

确实在AspectJ in Action中有一个例子。如果您查看目录,您会发现第 12.2 章就是您要查找的内容。买这本书是个好主意。我可以热情地推荐它。因为我不确定是否可以仅复制和粘贴本书的部分内容,所以我将在这里引用模板:

public aspect WormholeAspect {
    pointcut callerSpace(<caller context>) :
        <caller pointcut>;

    pointcut calleeSpace(<callee context>) :
        <callee pointcut>;

    pointcut wormhole(<caller context>, <callee context>) :
        cflow(callerSpace(<caller context>)) && 
        calleeSpace(<callee context>);

    // advice to wormhole
    before(<caller context>, <callee context>) :
        wormhole(<caller context>, <callee context>)
    {
            ... advice body
    }
}

Laddad在 TheServerSide.com 上有一篇旧文章,其中有一个更具体的示例。和书上的不一样,但很相似。

如您所见,在 AspectJ 中很容易做到,因为那里有cflow()切入点。我从未使用过 Guice,但它的AOP 介绍页面提到它们的实现是AOP 联盟规范的一部分。查看AOP 联盟 API,没有什么看起来像一个cflow()切入点,它围绕着构造函数和方法调用以及字段访问。

那么如果你想避免通过所有层传递参数,你可以在 Spring(没有 AspectJ)或 Guice 中做什么?显而易见的解决方案是ThreadLocal由调用者声明和管理(即分配但也清除)并由被调用者访问的变量。这不好,只是一种解决方法,以免使 API 膨胀。但这需要调用者和被调用者对他们想要共享的内容以及如何共享有一个共同的理解。在某种程度上,这种实现更像是一种反模式而不是一种模式。如果可以,请使用 AspectJ 以一种干净和模块化的方式解决这个问题,将要解决的问题封装在一个模块(方面)中。

于 2012-08-26T12:36:07.950 回答
1

一个简单的例子。想象一下,您有提供功能的上下文目标对象,这在某种程度上取决于上下文的状态:

class T {   
    public void foo() {
        System.out.println("T.foo()");
    }
}

class Context {
    public boolean isValid = true;
    public void doStuff() {
        T t = new T();
        t.foo();
    }
}

public class Main { 
    public static void main(String[] args) {
        Context c = new Context();
        c.doStuff();
    }
}

只有当成员设置为时,才能确保实例的实例可以在实例上Context调用的方面可能如下所示:foo()TisValidtrue

public aspect ContextStateValidation {

    pointcut MyContext(Context c) :
        execution(* Context.*()) && this(c);

    pointcut FooCalls(T t) :
        call(* T.foo()) && target(t);

    pointcut FooCallsInMyContext(Context c, T t) :
        cflow(MyContext(c)) && FooCalls(t);

    void around(Context c, T t) : FooCallsInMyContext(c, t) {
        if (c.isValid)
            proceed(c, t);
    }
}
于 2013-10-29T17:48:39.400 回答
0

不要使用虫洞模式……事实上,只有在你确定需要它时才使用 AOP,否则就不要使用它。

虫洞模式的缺点是你跳过了很多层……那是你真正想要的吗?:)

格茨,

克里斯托夫

于 2012-12-18T19:26:43.070 回答