使用AspectJ实现虫洞模式

时间:2012-08-26 11:03:29

标签: java aop guice aspectj

我正在寻找一个使用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”中有这样一个例子。

提前致谢。

3 个答案:

答案 0 :(得分:4)

确实在AspectJ in Action中有一个例子。如果您查看table of contents,您会注意到第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
    }
}

TheServerSide.com上有一个旧article by Laddad,其中有一个更具体的例子。它与书中的不一样,但相似。

正如您所看到的,在AspectJ中很容易做到,因为您有cflow()切入点。我从未使用过Guice,但它的AOP introduction页面提到它们的实现是AOP Alliance规范的一部分。看AOP Alliance API,看起来没有什么看起来像cflow()切入点,它只是构造函数&amp;方法调用加上字段访问。

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

答案 1 :(得分: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()时才能确保T的实例可以isValid实例调用true的方面以下方式:

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);
    }
}

答案 2 :(得分:0)

不要使用虫洞图案......事实上,只有在你确定需要的时候才使用AOP,否则请留下它。

虫洞模式的缺点是你跳过了很多层......你真正想要的是什么? :)

Grtz,

克里斯托夫