【Spring】4.1、什么是面向切面编程

1、前言

1.1、为什么需要面向切面编程(AOP)技术

在软件开发中,有一些需求需要散步在应用中的多处,称为横切关注点。

例如希望每一次操作,都记录下日志;当然我们可以在每一次操作都加上记录日志的代码,但是这样变得十分复杂和繁琐。

面向切面编程(AOP)的目的就是把这些横切关注点和业务逻辑相分离。

依赖注入(DI)实现了应用对象之间的解耦;而面向切面编程(AOP)实现了横切关注点和它们影响的对象之间的解耦。

1.2、什么是面向切面编程(AOP)技术

如上所述,切面可以帮助我们模块化横切关注点。

一般如果我们需要重用通用功能的话,常见的面向对象技术是继承或委托。

但是如果整个应用中都使用同样的基类,继承往往会导致一个脆弱的对象体系;

而使用委托可能需要对委托对象进行复杂的调用。

而切面提供了另一种可选方案:在一个独立的地方定义通用功能,通过声明的方式定义此功能用何种方式在何处应用,而无需修改受影响的类。横切关注点可以被模块化特殊的类,这些类称为切面。

这样做有2个好处:

a、每个关注点集中在一个地方,而不是分散到多出代码中;

b、服务模块更简洁,因为它们只关注核心代码,次要代码被转移到切面中。

2、AOP术语

通知(Advice)

通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。

Spring切面有5种类型的通知:

a、前置通知(Before):在目标方法被调用之前调用通知功能;

b、后置通知(After):在目标方法完成之后调用通知,此事不会关心方法的输出是什么;

c、返回通知(After-returning):在目标方法成功执行之后调用通知;

d、异常通知(After-throwing):在目标方法抛出异常后调用通知;

e、环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

连接点(Join point)

连接点是我们的程序可以应用通知的实际,是应用执行过程中能够插入切面的一个点。

切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

切点

切点(Poincut)

切点指切面所通知的连接点的范围。

一个切面不需要通知整个程序的连接点,通过切点,定义了切面所应用的范围。

通知定义了切面是“什么”以及“何时”执行,切点定义了“何处”需要执行切面。

切面(Aspect)

 切面是通知和切点的结合,定义了需要做什么,在何时,何处完成该功能。

引入(Introduction)

引入允许我们想现有的类添加新的方法或属性。

可以在不修改现有类的情况下,将新的方法和实例变量引入到该类中。

织入(Weaving)

织入是把切面应用到目标对象并创建新的代理对象的过程。

切面在指定的连接点被织入到目标对象中。

在目标对象的声明周期有几个点可以进行织入:

a、编译期:切面在目标类编译时被织入。这种方式需要特殊的编译期。AspectJ的织入编译器就是用这种方式织入切面。

b、类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。

      AspectJ 5的加载时织入(load-time weaving,LTW)就支持以这种方式织入切面。

c、运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会以目标对象动态创建一个代理对象。Spring AOP就是以这种方式织入切面的。

3、Spring对AOP的支持

不是所有的AOP框架都相同,比如在连接点模型上可能有强弱之分,有些允许在字段修饰符级别应用通知,而另一些只支持方法调用相关的连接点;织入切面的方式和时机也不同。

但是,AOP框架的基本功能,就是创建切点来定义切面所织入的连接点。

本书关注Spring AOP,同时Spring和AspectJ项目之间有大量协作,Spring对AOP支持有很多方面借鉴了AspectJ项目

Spring支持4种类型的AOP支持

a、基于代理的经典Spring AOP

  经典Spring AOP过于笨重和复杂,不作介绍。

b、纯POJO切面

  借助Spring的aop命名空间,可以将纯POJO转换为切面。

  实际上这些POJO知识提供了满足切点条件时所调用的方法。

  但这种技术需要XML配置。

c、@AspectJ注解驱动的切面

  提供以注解驱动的AOP。本质上还是Spring基于代理的AOP,但是编程模型修改为和AspectJ注解一致。

  这种方式好处在于不用使用XML。

d、注入式AspectJ切面(适用于Spring各版本)

  如果AOP需求超过了简单的方法调用(如构造器或属性拦截),则需要使用AspectJ来实现切面。

前3种都是Spring AOP实现的变体,基于动态代理,所以Spring对AOP的支持局限于方法拦截

Spring通知是Java编写的

Spring所创建的通知是标准的Java类编写的,我们可以使用Java开发IDE来开发切面。

而且定义通知所应用的切点通常会用注解或Spring XML编写,Java开发者都非常熟悉。

AspectJ与之相反,AspectJ最初是以Java语言扩展的方式实现的。

优点是通过特有的AOP语言,我们可以获得更强大和细粒度的控制,以及更丰富的AOP工具集。

缺点是需要额外学习新的工具和语法。

Spring在运行时通知对象

通过在代理类中包裹切面,Spring在运行期把切面织入到Spring管理的bean中。

代理类封装目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean。

代理拦截到方法调用时,会在调用目标bean方法之前执行切面逻辑。

知道应用需要被代理的bean时,Spring才会创建代理对象。如果使用的是ApplicationContext的话,在ApplicationContext从BeanFactory中加载所有bean的时候,Spring才会创建被代理的对象。

因为Spring运行时才创建代理对象,所以我们不需要特殊的编译器来织入Spring AOP的切面。

Spring只支持方法级别的连接点

因为Spring是基于动态代理,所以只支持方法连接点;但也足以满足绝大部分需求。

如果需要拦截字段和构造器,可以使用AspectJ和JBoss

猜你喜欢

转载自www.cnblogs.com/LiveYourLife/p/9023945.html