面向切面编程(AOP)作为面向对象编程(OOP)的一种补充,提出了另一种程序结构的思考方式。OOP中模块化的关键单元是类,而AOP模块的单位是一个切面。切面实现了对关注点的模块化,诸如贯穿于多种类型和对象的事务管理。(这种关注在AOP中通常被称为横切关注点)
SPRing的一个关键组件就是AOP框架。而Spring IoC容器没有依赖于AOP,那就意味着如果你不想,你不需要使用AOP。AOP补充了Spring IoC,提供了一个非常强大的中间件解决方案。
Spring 2.0 AOPSpring 2.0引入了一种更简单和更强大的方法来编写自定义方面,可以使用基于Schema的方法或是@aspectJ注解风格。 这两种风格都提供全类型通知和使用AspectJ切入点语言,同时仍然用SpringAOP进行组织。本章讨论了基于Spring 2.0 Schema和@AspectJ的AOP支持。 Spring 2.0 AOP仍然完全向后兼容Spring 1.2 AOP,Spring 1.2API等涉及较低级别的AOP支持在下面的章节中讨论。Spring框架中使用AOP
提供声明式企业服务,特别是作为EJB声明式服务的替代。最重要的服务是声明式事务管理。允许用户实现自定义切面,提供OOP的补充注意 如果您只对通用声明式服务,或其他预先打包的声明式中间件服务,如pooling感兴趣,你不需要直接使用Spring AOP,并且可以跳过本章的大部分内容。
让我们开始定义一些主要的AOP概念和术语。 这些术语不是Spring特有的,不幸的是,AOP术语不是特别直观; 然而,如果Spring使用自己的术语,它会更多混乱。 - 切面(Aspect)——即贯穿多个类的模块化关注点。事务管理是java企业应用程序中横切关注的一个很好的例子。 在Spring AOP中,切面使用普通类(基于Schema的方法)或被@Aspect注解的普通类(@AspectJ风格)来实现。 - 连接点(Joinpoint)——程序执行过程中的一个点,如一个方法的执行或异常的处理。在Spring AOP中,一个连接点总是代表一个方法的执行。 - 通知(Advice)——在切面的某个特定连接点发生的动作。 不同类型的通知包括”around”,”before”和”after”(通知类型在下面讨论)。许多AOP框架,包括Spring,把一个通知建模为拦截器,连接点周围一般维持一系列的拦截器。 - 切入点(Point Cut)——匹配连接点的术语。通知和切入点表达式相关联并且在任何匹配切入点的连接点运行。(例如,在特定的名称处执行方法)。通过切入表达式匹配的连接点的概念是AOP的核心,Spring默认情况下使用AspectJ切入点表达式语言。 -引言(Introduction)——声明代表一个类型的其他方法或字段。Spring AOP允许你向任何通知的对象引入新接口(和相应的实现)。例如,你可以使用引入来使一个bean实现 IsModified接口,以便简化缓存。(在AspectJ社区,引言被称为的类型间声明。) - 目标对象(Target object)——被一个或多个切面通知的对象。 也被称作被通知对象。因为Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理对象。 - AOP代理(AOP proxy)——以AOP框架创建的对象为了实现切面契约(通知方法执行等)。 在Spring框架中,AOP代理将是一个JDK动态代理或CGLIB代理。 - 编织(Weaving)——连接切面和其他应用程序类型或对象来创建一个被通知的对象。这个可以在编译期间(使用AspectJ编译器)、加载期间、或者运行期间完成。Spring AOP与其他纯Java AOP框架一样,在运行期执行织入。
通知类型:
前置通知:一个连接点之前执行,但它不能阻止该连接点正在执行的流程(除非它抛出异常)。返回后通知:一个连接点被执行的正常完成后的通知。例如,如果一个方法返回而不抛出异常。抛出后通知 :在方法抛出异常退出后执行的通知。后置(最终)通知 :不管通过什么方式退出连接点,都执行的通知(正常或异常返回)。环绕通知:环绕通知围绕着类似于方法引用的连接点。这是最强大的一种通知。环绕通知能在方法引用之前和之后执行自定义行为。它还负责选择是继续执行到连接点还是通过返回自己的返回值或者抛出异常来绕过通知方法的执行。环绕通知是最普通的一种通知。由于Spring AOP提供了像AspectJ一样的全部范围的通知类型,我们建议您在能实现要求功能的情况下,使用最简化的通知类型。例如,如果你仅仅需要用方法的返回值更新缓存,你最好实现一个返回后通知而不是环绕通知,虽然环绕通知也能完成相同的功能。使用大多数特定的通知类型都能提供一个简单的编程模型并且很少有潜在错误。例如,在环绕通知中,你不需要在JoinPoint上调用proceed()方法。因此,你不可能存在调用失败。
在Spring 2.0中,所有通知参数都是静态类型的,因此您可以使用适当类型(例如从方法执行的返回值的类型)的通知参数,而不是对象数组。连接点的概念是AOP的关键,它匹配切入点,区别于只提供拦截功能的老技术。 切入点使得通知能够单独定位面向对象层次结构。 例如,一个提供声明性事务管理的环绕通知可以应用于跨越多个对象的一组方法(例如服务层中所有业务操作)。
Spring AOP是纯Java实现,不需要特殊的编译过程。Spring AOP不需要控制类加载器的层次结构,因此它适用于Servlet容器中或者应用服务器。
Spring AOP目前仅支持方法执行连接点(在Spring Bean上通知方法的执行),虽然可以在不影响到Spring AOP核心API的情况下加入对成员变量拦截器的支持,但Spring并没有实现成员变量拦截器。 如果你需要把对成员变量的访问和更新也作为通知的连接点,可以考虑其它语言,例如AspectJ。
Spring AOP的AOP实现方式不同于其他大部分AOP框架。它的目的不是去提供最完整的AOP实现(尽管Spring AOP有这个能力),而是提供AOP实现和Spring IOC的紧密结合,来帮助解决企业应用中的常见问题。
因此,Spring框架的AOP功能通常都是和Spring IOC容器结合使用。切面的配置使用标准的bean语法定义(尽管允许使用强大的“autoproxying”功能),这是Spring AOP区别于其他AOP实现的关键不同。有些情况下,如细粒度对象的切面,使用Spring AOP并不一定简单和高效。这种情况下使用AspectJ是最好的选择。不过,经验告诉我们,Spring是经得起考验的AOP框架,在企业Java应用中的大多数问题它都能提供优秀的解决方案。
Spring AOP从来没有打算通过提供一种全面的AOP解决方案来取代AspectJ。我们相信无论是像Spring这种基于代理的框架亦或是像AspectJ这种成熟的框架,都是很有价值的,并且,他们之间的关系更应该是互补而不是竞争的关系。Spring利用AspectJ无缝集成Spring AOP和IOC,使得所有的AOP应用完全融入基于Spring的应用体系。这种集成并不影响Spring AOP API或AOP联盟API,Spring AOP保持向后兼容。
注意 Spring的一个核心原则就是非侵入性,也就是说你不应该在你的业务模型中强制引用框架特定的类或者接口,但是,在某些地方,Spring框架会给你选择在你的代码库中引入Spring框架特定的依赖:提供这种选择的理由是,在某些情况下它可能更容易阅读或使代码以某种特定的方式实现功能。 Spring框架几乎一直给你提供一种选择:你可以自己决定,以选择适合你自己的特定场景。与本章相关的选择正是AOP框架(AOP风格)的选择。你可以选择AspectJ和/或Spring AOP,你也可以选择 @AspectJ注解方式或Spring xml配置文件的方式。这章中选择首先介绍@AspectJ注解的方式,并不能表明Spring团队更喜欢@Aspect注解方式而不是Spring XML配置的方式。关于如何选择哪种方式请参看
Spring AOP 缺省使用标准的JDK动态代理作为AOP代理。任何接口(或接口组)都可以被代理。它也可以使用CGLIB代理。 对于需要代理类而不是代理接口的时候CGLIB代理是很有必要的。如果业务对象没有实现接口,则默认使用CGLIB。此外,面向接口编程也是一个最佳实践,业务对象通常都会实现一个或多个接口。此外,还可能会强制使用CGLIB,在这种(希望很少)情况下,你需要通知一个未在接口上声明的方法,或者您需要传递代理对象的地方作为具体类型的方法。
新闻热点
疑难解答