当前位置: 代码迷 >> 综合 >> 5. 使用Spring进行面向切面编程【spring 核心技术 翻译】
  详细解决方案

5. 使用Spring进行面向切面编程【spring 核心技术 翻译】

热度:50   发布时间:2024-01-28 14:07:06.0

面向切面程序设计(AOP)通过提供另一种考虑程序结构的方法来补充面向对象程序设计(OOP)OOP中模块性的关键单元是类,而AOP中模块性的单元是切面。切面支持跨多个类型和对象的关注点(如事务管理)的模块化。(在AOP文献中,这样的关注点通常被称为“横切”关注点。)
Spring的关键组件之一是AOP框架。虽然Spring IoC容器不依赖于AOP(这意味着如果您不想使用AOP,就不需要使用AOP),但AOP对Spring IoC进行了补充,提供了一个非常强大的中间件解决方案。

带有AspectJ切入点的Spring AOP
Spring通过使用基于模式的方法或@AspectJ注释风格提供了编写自定义方面的简单而强大的方法。这两种风格都提供了完全类型的通知和AspectJ切入点语言的使用,同时仍然使用Spring AOP进行编织。
本章讨论基于模式和@ aspectj的AOP支持。下一章将讨论底层AOP支持。

在Spring框架中使用AOP来:

  • 提供声明式企业服务。此类服务中最重要的是声明式事务管理。
  • 让用户实现自定义方面,用AOP补充OOP的使用。

如果您只对通用的声明性服务或其他预先打包的声明性中间件服务(如池)感兴趣,那么您不需要直接使用Spring AOP,可以跳过本章的大部分内容。

5.1。AOP概念

让我们从定义一些核心的AOP概念和术语开始。这些术语并不是spring特有的。不幸的是,AOP术语不是特别直观。但是,如果Spring使用自己的术语,就更令人困惑了。

  • 切面:Aspect跨多个类的关注点的模块化。事务管理是企业级Java应用程序中横切关注点的一个很好的例子。在Spring AOP中,方面是通过使用常规类(基于模式的方法)或使用@Aspect注释的常规类(@AspectJ风格)来实现的。
  • 连接点:Join point:程序执行期间的一个点,例如方法执行或异常处理期间的一个点。在Spring AOP中,连接点总是表示方法执行。
  • 通知Advice:切面在特定连接点上采取的操作。不同类型的建议包括“周围”、“之前”和“之后”的建议。(稍后讨论通知类型。)许多AOP框架(包括Spring)将通知建模为拦截器,并围绕连接点维护拦截器链。
  • 切入点Pointcut:匹配连接点的谓词。通知与切入点表达式相关联,并在切入点匹配的任何连接点上运行(例如,具有特定名称的方法的执行)。由切入点表达式匹配的连接点的概念是AOP的核心,Spring在默认情况下使用AspectJ切入点表达式语言。
  • 介绍Introduction:代表类型声明其他方法或字段。Spring AOP允许向任何被建议的对象引入新的接口(以及相应的实现)。例如,您可以使用一个介绍使一个bean实现一个IsModified接口,以简化缓存。(在AspectJ社区中,介绍称为类型间声明。)
  • 目标对象Target object:由一个或多个切面通知的对象。也称为“通知对象”。因为Spring AOP是通过使用运行时代理实现的,所以这个对象始终是一个代理对象。
  • AOP代理AOP proxy:AOP框架为了实现切面契约(通知方法的执行等等)而创建的对象。在Spring框架中,AOP代理是JDK动态代理或CGLIB代理。
  • 编织Weaving:将切面与其他应用程序类型或对象链接,以创建建议对象。这可以在编译时(例如使用AspectJ编译器)、加载时或运行时完成。与其他纯Java AOP框架一样,Spring AOP在运行时执行编织。

Spring AOP包括以下类型的通知:

  1. Before advice :在连接点之前运行但不能阻止执行流继续到连接点的通知(除非它抛出异常)。
  2. 返回通知后After returning advice:通知将在连接点正常完成后运行(例如,如果方法返回时没有抛出异常)。
  3. 抛出通知后After throwing advice:如果方法通过抛出异常而退出,则执行通知。
  4. 通知之后(最后)After (finally) advice:无论连接点以何种方式退出(正常或异常返回),都要执行通知。
  5. 环绕通知Around advice:围绕连接点(如方法调用)的通知。这是最有力的建议。Around通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续到连接点,还是通过返回自己的返回值或抛出异常来简化建议的方法执行。

Around advice是最常见的一种通知。由于Spring AOP像AspectJ一样提供了完整的通知类型,我们建议您使用功能最弱的通知类型来实现所需的行为。例如,如果只需要用方法的返回值更新缓存,那么最好实现一个after return advice,而不是around advice,尽管around advice可以完成同样的事情。使用最特定的通知类型可以提供更简单的编程模型,出错的可能性更小。例如,您不需要在用于around通知的JoinPoint上调用proceed()方法,因此,您不会无法调用它。

所有通知参数都是静态类型的,这样您就可以使用适当类型的通知参数(例如,从一个方法执行返回值的类型),而不是对象数组。

由切入点匹配的连接点的概念是AOP的关键,这区别于只提供拦截的旧技术。切入点使通知能够独立于面向对象的层次结构作为目标。例如,您可以应用around通知,为一组跨越多个对象(如服务层中的所有业务操作)的方法提供声明性事务管理。

5.2。Spring AOP的功能和目标

Spring AOP是用纯Java实现的。不需要特殊的编译过程。Spring AOP不需要控制类加载器的层次结构,因此适合在servlet容器或应用服务器中使用。

Spring AOP目前只支持方法执行连接点(通知方法在Spring bean上的执行)。虽然可以在不破坏Spring AOP核心api的情况下添加对字段拦截的支持,但没有实现字段拦截。如果需要通知字段访问和更新连接点,请考虑使用AspectJ之类的语言。

Spring AOP实现AOP的方法不同于大多数其他AOP框架。其目的不是提供最完整的AOP实现(尽管Spring AOP非常有能力)。相反,其目的是提供AOP实现和Spring IoC之间的紧密集成,以帮助解决企业应用程序中的常见问题。

因此,例如,Spring框架的AOP功能通常与Spring IoC容器一起使用。方面是通过使用普通的bean定义语法来配置的(尽管这允许强大的“自动代理”功能)。这是与其他AOP实现的一个关键区别。使用Spring AOP不能轻松或有效地完成一些事情,比如通知非常细粒度的对象(通常是域对象)。在这种情况下,AspectJ是最好的选择。然而,我们的经验是,Spring AOP为企业级Java应用程序中的大多数问题提供了一个优秀的解决方案,而这些问题都是符合AOP的。

Spring AOP从来没有努力与AspectJ竞争来提供全面的AOP解决方案。我们相信基于代理的框架(如Spring AOP)和成熟的框架(如AspectJ)都是有价值的,它们是互补的,而不是竞争的。Spring与AspectJ无缝地集成了Spring AOP和IoC,以便在一致的基于Spring的应用程序体系结构中启用AOP的所有使用。这种集成不会影响Spring AOP API或AOP Alliance API。Spring AOP保持向后兼容。有关Spring AOP api的讨论,请参阅下面的章节。

Spring框架的核心原则之一是非侵入性。这就是不应该强迫您将特定于框架的类和接口引入您的业务或领域模型的思想。然而,在某些地方,Spring框架确实为您提供了将特定于Spring框架的依赖项引入代码库的选项。给您提供这些选项的理由是,在某些场景中,这样可能更容易阅读或编写某些特定的功能片段。然而,Spring框架(几乎)总是为您提供选择:您可以自由地做出明智的决定,选择哪个选项最适合您的特定用例或场景。

与本章相关的一个选择是选择哪个AOP框架(以及哪种AOP风格)。您可以选择AspectJ、Spring AOP或两者都有。您还可以选择@AspectJ注释风格的方法或Spring XML配置风格的方法。本章选择首先介绍@AspectJ风格的方法并不意味着Spring团队更喜欢@AspectJ注释风格而不是Spring XML配置风格。
有关每种风格的“为什么和在哪里”的更完整的讨论,请参见选择使用哪种AOP声明风格。

5.3。AOP代理

Spring AOP默认为AOP代理使用标准JDK动态代理。这允许代理任何接口(或一组接口)。
Spring AOP也可以使用CGLIB代理。这对于代理类而不是接口是必要的。默认情况下,如果业务对象没有实现接口,则使用CGLIB。由于使用接口而不是类编程是一种很好的实践,因此业务类通常实现一个或多个业务接口。在需要通知接口上没有声明的方法,或者需要将代理对象作为具体类型传递给方法的情况下(希望很少),可以强制使用CGLIB。
掌握Spring AOP是基于代理的这一事实很重要。请参阅理解AOP代理,了解这个实现细节的真正含义。

  相关解决方案