Spring FrameWork从入门到NB - Spring AOP - 概念

什么是AOP

AOP - Aspect Oriented Programming的缩写,面向切面编程。

面向切面编程AOP是面向对象程序设计OOP的一个补充或扩展,是为了解决OOP在一些共性问题上的不足应运而生的。比如记录日志、事务处理、性能分析等等与业务无关的需求,需要发生在很多类的很多方法上,而需求是一样的:比如日志处理就是在方法执行前或执行后记录日志,事务处理需要在方法执行前开启事务、在方法执行结束后提交或回滚事务。

AOP出现之前,老程序员应该都有记忆(亲身经历),我们需要在每一个需要事务处理的方法中都添加逻辑一模一样的代码:获取连接、开启事务。然后在方法执行完成后也需要添加一模一样的代码:如果方法执行成功则提交事务、执行失败或发生异常则回滚事务。

这些代码写多了(其实不可能少、肯定会很多),能让程序员痛苦不堪、怀疑人生!

然后,AOP横空出世。

AOP其实最终要实现的功能就是:不侵入代码的前提下,实现上述这些公共逻辑。

我艹,简直不要太爽…

当然,横空出世的不是Spring AOP,那个时候还没有Spring。AOP横空出世之后,为了统一AOP的概念、属于以及接口,出现了AOP联盟,Spring AOP也遵循AOP联盟的相关规范。之后,AOP江湖逐渐被AspectJ统治,Spring从2.0开始就无缝集成了AspectJ。

AOP的底层逻辑其实不复杂,就是通过代理:需要实现这些公共逻辑的类,我们可以称之为目标类,不修改目标类、却要改变(或者叫增强)其执行逻辑,用脚指头都能想到是通过代理。

AOP的早期版本(AspectJ 1.0)通过静态代理实现,静态代理是在编译期修改目标类代码、生成代理类代码的方式,运行会比较快(因为在编译器就生成代理对象代码了),但是明显的缺点就是稍有修改就需要重新编译打包,不可谓不繁琐。

之后的AOP版本通过动态代理实现,动态代理我们也很熟悉,前面专门分析过,是在运行期动态生成目标类的代理对象的,无非两种方式:

  1. JDK动态代理,基于接口实现。
  2. Cglib动态代理,生成目标类的扩展类实现。
    具体请参考动态代理 java原生 vs Cglib

所以我们现在应该明白,AOP是什么,为什么会有AOP,以及AOP的底层原理。

AOP术语

我一直在想,对于AOP的初学者,是通过直接上手练习的方式入门,还是按照常规的方式:先学习AOP的理论,掌握AOP的概念和术语,然后再通过简单示例加强理解。

常规学习路线应该是后者,然而,虽然AOP的概念和底层逻辑很好理解,但是AOP的术语却极具迷惑性、非常不友好,很难理解。

但是确实没有办法,要学习AOP,那么AOP的术语就是迈不过去的一道坎,无论如何也是要有所了解的。

所以,来吧,看看AOP相关术语,我们尽量用简单明了的语言来解释。

  1. Target object: 目标对象,指的就是我们的业务对象,我们要通过AOP技术增强目标对象的方法(对于Spring Aop来说,只增强目标对象的方法,对于AOP联盟来说,还可以增强属性)。
  2. AOP proxy:AOP代理对象,前面已经说过AOP的底层逻辑就是通过代理实现的,AOP proxy指的就是目标对象的代理对象。
  3. Join point:连接点,其实是AOP要增强的点,对于Spring AOP来说,我们要增强的其实就是目标对象的方法执行过程,所以连接点就是方法执行。
  4. Pointcut:切点,指的是满足条件的连接点,或者可以理解为满足切入连接点的条件。切点通过表达式的方式定义条件,满足切点条件的时候,执行切入动作、增强连接点规定的方法。
  5. Advice:增强逻辑,是AOP要实现的目的的体现,比如实现事务管理的AOP,Advice就是开启及提交或回滚事务,日志处理的AOP,Advice就是在连接点方法执行前后打印日志。
  6. Aspect: 切面,简单说就是体现连接点Join point定义、Pointcut定义、以及Advice逻辑实现的模块(可以简单理解为:一组类)。Spring Aop中通过xml配置文件指定、或者通过注解@Aspect指定。
  7. Introduction:引荐(其实不翻译最好,AOP的这些术语其实都是这样,不翻译、直呼其英文名最好),可以这么理解:AOP切面类中,除为了实现目标类方法增强之外,还可以定义其他的属性或方法,去帮助实现AOP之外的额外的功能。
  8. Weaving:织入,就是根据Aspect的定义,对符合条件的目标对象,通过动态代理技术增强其方法逻辑、生成代理对象的过程。生成代理对象之后,就相当于我们把Advice“织入”到代理对象中了。

Spring AOP的Advice类型:

  1. Before advice:在join point执行前生效,但是advice没有拦截阻止join point的能力,原因是Spring Aop的Before advice对目标对象的join point的调用控制权并不在切面类中,而是交给了框架,所以除非有异常发生、否则无法拦截或阻止join point方法的执行。
  2. After returning advice: join point正常执行完成并返回后生效。
  3. After throwing advice: join point调用异常后生效。
  4. After (finally) advice: join point调用后生效,不管正常结束或抛出异常。
  5. Around advice: Spring AOP功能最为强大的advice,功能强大的原因是:对join point的调用是在切面完成的,所以,切面编写者有权对join point调用前、调用后的逻辑做全面的控制,比如可以在调用前进行逻辑判断后阻止join point的调用,返回前面自定义的返回值或者抛出异常,也可以在join point调用后根据其返回值做任意的处理。

既然Around advice可以对join point做调用前、调用后的增强,而且其功能最为强大,那是不是就意味着before和after增强就没有存在的意义了呢?有关这一点,Spring官网其实也给出了一些建议:

Around advice is the most general kind of advice. Since Spring AOP, like AspectJ, provides a full range of advice types, we recommend that you use the least powerful advice type that can implement the required behavior. For example, if you need only to update a cache with the return value of a method, you are better off implementing an after returning advice than an around advice, although an around advice can accomplish the same thing. Using the most specific advice type provides a simpler programming model with less potential for errors. For example, you do not need to invoke the proceed() method on the JoinPoint used for around advice, and, hence, you cannot fail to invoke it.

一句话:选择刚好能满足自己需求的Advice、而不建议选择功能远超出自己需求的Advice,一方面简化切面逻辑,另一方面,减少调用错误的发生概率。

Spring AOP vs AspectJ

Spring AOP仅支持对方法的切入,而AspectJ支持属性切入。

有关Spring AOP的能力和目标,其实Spring官网有专门的说明:

Spring AOP’s approach to AOP differs from that of most other AOP frameworks. The aim is not to provide the most complete AOP implementation (although Spring AOP is quite capable). Rather, the aim is to provide a close integration between AOP implementation and Spring IoC, to help solve common problems in enterprise applications.

Spring AOP与大部分的AOP框架不同,Spring AOP的目标并不是提供一个功能强大的AOP实现(虽然说Spring AOP已经比较强大了)。反而,Spring AOP的髰提供一个将AOP和Spring IoC紧密集成的框架从而对企业级应用的开发提供帮助。

Thus, for example, the Spring Framework’s AOP functionality is normally used in conjunction with the Spring IoC container. Aspects are configured by using normal bean definition syntax (although this allows powerful “auto-proxying” capabilities). This is a crucial difference from other AOP implementations. You cannot do some things easily or efficiently with Spring AOP, such as advise very fine-grained objects (typically, domain objects). AspectJ is the best choice in such cases. However, our experience is that Spring AOP provides an excellent solution to most problems in enterprise Java applications that are amenable to AOP.

Spring AOP的功能通常可以通过Spring Ioc容器提供,切面可以通过正常的bean definition完成配置,这是与其他AOP框架的显著不同点。我们不太容易通过Spring框架实现细粒度的AOP控制。如果你有这样的需求,AspectJ是更好的选择。其实,Spring AOP已经可以解决企业应用开发中碰到的绝大部分AOP相关的问题。

Spring AOP never strives to compete with AspectJ to provide a comprehensive AOP solution. We believe that both proxy-based frameworks such as Spring AOP and full-blown frameworks such as AspectJ are valuable and that they are complementary, rather than in competition. Spring seamlessly integrates Spring AOP and IoC with AspectJ, to enable all uses of AOP within a consistent Spring-based application architecture. This integration does not affect the Spring AOP API or the AOP Alliance API. Spring AOP remains backward-compatible. See the following chapter for a discussion of the Spring AOP APIs.

Spring AOP从来没想与AspectJ竞争、去提供一个强大的AOP解决方案。我们相信基于代理的框架比如Spring AOP、以及全功能的框架比如AspectJ,都是有价值的,是互补的关系,而不是竞争的关系。Spring框架很好的继承了Spring Aop、Spring IoC、以及AspectJ,从而使用户可以在Spring框架下、基于Spring框架来使用Aop。这种集成并没有影响Spring Aop API以及AOP联盟的API,Spring AOP确保向下兼容。

Spring AOP与AspectJ支持的连接点的区别:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o98KrtzO-1688996815295)(/img/bVc8IWb)]

上一篇 Spring FrameWork从入门到NB - ApplicationContext

你可能感兴趣的:(spring,java,数据库)