【问题标题】:Implementing a wormhole pattern using AspectJ使用 AspectJ 实现虫洞模式
【发布时间】:2012-08-21 04:59:34
【问题描述】:

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

提前致谢。

【问题讨论】:

    标签: java aop guice aspectj


    【解决方案1】:

    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() 切入点,它围绕着构造函数和方法调用以及字段访问。

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        【解决方案3】:

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

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

        格兹,

        克里斯托夫

        【讨论】:

        • 嗨,我喜欢使用虫洞模式来保持我的方法签名干净。例如,如果我想在我的调用流中传递大量上下文和其他信息,这纯粹是实现的副作用,与手头的用例几乎没有关系。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-20
        • 1970-01-01
        • 2014-08-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多