【问题标题】:Crosscut concerns in middle of methods方法中间的横切关注点
【发布时间】:2010-12-28 16:44:34
【问题描述】:

AOP(例如 AspectJ、SpringAOP)在以下方法的切入点处处理(建议)横切关注点很方便,

“三明治”代码

methodA {
    crosscut code
    user code A
    crosscut code
}

methodB {
    crosscut code
    user code B
    crosscut code
}

AOP 是否易于横切关注点与下面的用户代码重叠?怎么样?

“意大利面”代码

methodX {
    user code x1
    crosscut code

    user code x2
    crosscut code
}

methodY {

    user code y1
    crosscut code

    user code y2
    crosscut code
}

谢谢!

【问题讨论】:

    标签: java spring aop aspectj spring-aop


    【解决方案1】:

    Spring AOP 无济于事,因为它只理解 execution() 切入点。

    AspectJ 包含更多切入点,包括 insidecode() 构造,这听起来像你想要的:

    withincode(* YourClass.methodX(. .))
    

    这让您可以建议给定方法执行中的所有连接点

    阅读AspectJ in Action 了解更多信息,这是一本关于 AspectJ 和 Spring AOP 的非常好的书。


    编辑:

    这里是一些示例代码:

    package com.dummy.aspectj;
    
    import java.util.Arrays;
    import java.util.Collections;
    
    public class DummyClass{
    
        public static void main(final String[] args){
            System.out.println(Arrays.asList("One", Collections.singleton("Two")));
            System.out.println("Enough?");
        }
    
    }
    
    package com.dummy.aspectj;
    
    import java.util.Arrays;
    
    public aspect DummyAspect{
    
        pointcut callWithinMain() : 
            withincode(* com.dummy.aspectj.DummyClass.main(..)) // anything inside DummyClass.main
            && call(* *.*(..));                                 // but only method calls
    
        before() : callWithinMain() {
            System.out.println("\n***************************************************");
            System.out.println("** Calling:\n**\t"
                + thisJoinPointStaticPart.getSignature()
                + "\n** with arguments:\n**\t "
                + Arrays.deepToString(thisJoinPoint.getArgs()) );
            System.out.println("***************************************************\n");
        }
    
    }
    

    从 Eclipse / AJDT 运行 DummyClass 会生成以下输出:

    ***************************************************
    ** Calling:
    **  Set java.util.Collections.singleton(Object)
    ** with arguments:
    **   [Two]
    ***************************************************
    
    
    ***************************************************
    ** Calling:
    **  List java.util.Arrays.asList(Object[])
    ** with arguments:
    **   [[One, [Two]]]
    ***************************************************
    
    
    ***************************************************
    ** Calling:
    **  void java.io.PrintStream.println(Object)
    ** with arguments:
    **   [[One, [Two]]]
    ***************************************************
    
    [One, [Two]]
    
    ***************************************************
    ** Calling:
    **  void java.io.PrintStream.println(String)
    ** with arguments:
    **   [Enough?]
    ***************************************************
    
    Enough?
    

    【讨论】:

    • 你有一个方便的例子可以放在这里吗?感谢赐教!
    【解决方案2】:

    虽然某些 AOP 实现可能允许您这样做,但这可能表明需要将这些方法重构为更加组合的方法,因为如果需要将关注点横切到方法的中间,它们可能会做的太多。 这样做会给你这个:

    methodX 
    {
        usercodemethod1();
        usercodemethod2();
    }
    
    usercodemethod1
    {
        user code x1
        crosscut code
    }
    
    usercodemethod2
    {
        user code x2
        crosscut code
    }
    

    【讨论】:

    • 我们根据最佳实践进行重构。一般来说,将购物车重构为 AOP 是一种好的做法吗?如果不是这样,我们承认 AOP 倾向于相当约束问题域,例如事务分界绿灯,日志记录红灯。
    • 我不会说应该重构只是为了迎合 AOP,但是正如 @seanizer 所提到的,spring 对此无济于事,所以如果你要这样做,这可能是你最好的选择route - 任何基于代理(运行时)的 AOP 通常不支持将代码编织到方法的中间
    • @saret:这不适用于基于代理的 aop。当 methodX 调用 usercodemethod1 (假设它们在同一个类中)时,它不会调用代理,而是调用实际的类(您已经在代理中),因此建议没有机会执行。所以实现这一点的唯一方法是让整个工作流从外部访问(客户端调用 usercodemethod1,然后是 usercodemethod2 等),这将严重违反 DRY 原则。
    • @seanizer 如果这些方法是可覆盖的(例如受保护的虚拟方法),那么代理可以将代码注入其中
    • 这需要 cglib,这对于基于接口的 jdk 代理(这是 spring aop 的标准方法)是不可能的。
    猜你喜欢
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-19
    • 2014-07-05
    • 2011-08-01
    相关资源
    最近更新 更多