【问题标题】:Run-time AOP vs Compile-time AOP运行时 AOP 与编译时 AOP
【发布时间】:2016-09-12 10:44:36
【问题描述】:

这两种AOP框架的优缺点是什么?我使用 Unity 作为我的 aop 框架,但我猜想 postsharp 之类的编译时 aop 框架可能比运行时 aop 框架有更好的性能?看起来运行时 aop 框架使用反射来实现注入。

【问题讨论】:

    标签: architecture aop


    【解决方案1】:

    我不是 .NET 人,但我了解 Java 生态系统中的 AOP 世界,尤其是 AspectJ 和 Spring AOP。基本上有4种方面编织:

    • 源代码编织:方面代码作为源代码语句注入到您的应用程序源代码中。这是某种预处理器方法。现在 Java 世界中没有任何 AOP 框架使用这种方法,但在 AOP 的早期曾经有一些。
      • 如果操作正确,优势将是在运行期间完全独立于任何运行时库或特殊 AOP 编译器。
      • 缺点是源代码臃肿,编译前有预处理/代码生成步骤。您总是需要生成的源代码进行调试。
    • 编译时编织:方面代码由特殊的编译器编织到您的应用程序中。
      • 优点是方面编织没有运行时开销。您唯一需要的是类路径上的小型运行时库。
      • 缺点是,如果您想将方面编织到应用程序中,则不能将决定推迟到运行时。但这只是在处理并非一直需要的调试或跟踪方面时才会出现的问题。另一个缺点是这种方法仅适用于您控制的代码,即您需要拥有源代码。它不适用于 3rd 方库。
    • 二进制编织: 方面代码在编译后而不是在编译期间被编织到现有的类文件中。
      • 优点是它也适用于您没有源代码的第 3 方代码。这种方法也可以与编译时编织混合使用。您还可以避免加载时编织的开销(见下文)。
      • 缺点类似于编译时编织:一旦将切面编织到代码中,就无法取消应用切面,只能通过诸如if() 之类的切入点停用其执行。但这可能非常有效。
    • 加载时织入 (LTW): 织入代理/库会在您的 VM/容器启动时提前加载。它获取一个配置文件,其中包含描述哪些方面应该被编织到哪些类中的规则。
      • 优点是您可以动态决定是否编织/编织什么。如果通过字节码转换而不是通过动态代理或反射(见下文)完成,则生成的字节码与通过编译时或二进制编织创建的字节码同样有效。另一个优点是,就像二进制编织一样,它适用于您自己的代码以及第 3 方代码,只要编织代理可以“看到”它,即它发生在子类加载器中。
      • 缺点是应用程序启动期间的一次性编织开销,因为编织是在类加载发生时完成的。
    • 基于代理的 LTW: 这种特殊的 LTW 形式由 Spring AOP 使用,而 AspectJ 使用上面列出的前 3 种形式。它通过为方面目标创建动态代理(即子类或接口实现)来工作。
      • 除了您选择的框架(例如 Spring)恰好支持它之外,我想不出任何特殊优势。
      • 由于基于代理的方法,缺点是对公共、非静态方法和运行时开销的限制。它也不捕获内部方法调用,即当代理类调用它自己的方法之一时,因为这些调用未被代理捕获。不支持特殊类型的切入点,例如构造函数拦截、成员变量读/写访问等等,这使得这更像是一种“AOP lite”方法。但这足以满足您的目的。

    一般来说,像 AspectJ 这样好的方面编译器会创建非常高效的字节码,并且不会在运行时严重依赖反射。如果您选择的方面框架确实依赖于反射,那么它可能不是很快。但也许它足够快,这取决于您使用方面的程度。

    可能我已经写太多了,但我可以写更多。这就是我现在停下来的原因。此外,这类问题不太适合 StackOverflow,因为它可能导致哲学讨论和基于意见的辩论。我希望我能做到相当客观/公正。

    【讨论】:

    • 那是很棒的解释。我们不能说aspectJ不使用反射吗?你还说 AspectJ 做了这三个:编译时、二进制、加载时,我们可以选择使用哪一个还是在内部发生?
    • Amir,您可以通过阅读documentation 了解有关 AspectJ 的更多信息。我建议尝试使用它,而不是问自己关于它的理论问题。至于第二个问题,您作为开发人员决定要使用哪种编织类型。如果您没有相应地配置构建环境,AspectJ 不会做任何事情。
    • @kriegaex aspectj 编译器比 java 编译器有什么缺点吗?假设我们使用编译时编织,并且由于 aspectj 编译器而面临一个问题。在我们无法修复 aspectj 编译器的情况下,我们将不得不进行大量更改以使事情再次正常工作。简而言之,编译时编织似乎是最好的选择,但 aspectj 编译器似乎是一个交易破坏者。您对此有何看法?
    • 我的看法是:有些人会为每个问题找到解决方案。其他人在每个解决方案中都发现了问题。此外,AspectJ 编译器是 Eclipse Java 编译器的一个定期更新的分支,并且维护得非常好。与 Oracle JVM 相比,它更容易引起维护者的注意。我的建议是:也要看到机会,而不仅仅是风险。我在这里看不到任何“破坏交易”。
    • 非常感谢您的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多