什么是AOP
AOP(Aspect Oriented Programming),即面向切面编程,对于面向对象编程(OOP)来说,AOP是一种补充。面向对象编程是软件开发的最基本抽象思想,OOP使得代码脱离了面向过程这种高耦合的代码开发模式,同时OOP引入了封装、继承、多态等概念建立了一种纵向依赖关系
,从代码复用的角度看,OOP复用了同一继承链上的代码
,也就是说OOP是纵向代码复用
,无法横向代码复用。OOP的缺陷导致了很多公共代码需要重复引用重复编写,这也是Java项目工程中常常需要封装很多静态类、公共类的原因
,但对于Java程序员来说这不是一件很正常的事情吗?就像吃饭要用筷子夹,喝汤要用勺子舀一样。而AOP的思想却是关注横向切面
,相当于在纵向关系链中横切一刀,将那些业务模块的公共调用代码封装起来,形成一个切面(Aspect),从而减少了公共代码的引用点,提高了可维护性。下图是小编绘制的一副AOP与OOP关系的小图:
AOP(Aspect Oriented Programming),即面向切面编程,对于面向对象编程(OOP)来说,AOP是一种补充。面向对象编程是软件开发的最基本抽象思想,OOP使得代码脱离了面向过程这种高耦合的代码开发模式,同时OOP引入了封装、继承、多态等概念建立了一种纵向依赖关系,从代码复用的角度看,OOP复用了同一继承链上的代码,也就是说OOP是纵向代码复用,无法横向代码复用。OOP的缺陷导致了很多公共代码需要重复引用重复编写,这也是Java项目工程中常常需要封装很多静态类、公共类的原因,但对于Java程序员来说这不是一件很正常的事情吗?就像吃饭要用筷子夹,喝汤要用勺子舀一样。而AOP的思想却是关注横向切面,相当于在纵向关系链中横切一刀,将那些业务模块的公共调用代码封装起来,形成一个切面(Aspect),从而减少了公共代码的引用点,提高了可维护性。下图是小编绘制的一副AOP与OOP关系的小图:
AOP(Aspect Oriented Programming),即面向切面编程,对于面向对象编程(OOP)来说,AOP是一种补充。面向对象编程是软件开发的最基本抽象思想,OOP使得代码脱离了面向过程这种高耦合的代码开发模式,同时OOP引入了封装、继承、多态等概念建立了一种纵向依赖关系,从代码复用的角度看,OOP复用了同一继承链上的代码,也就是说OOP是纵向代码复用,无法横向代码复用。OOP的缺陷导致了很多公共代码需要重复引用重复编写,这也是Java项目工程中常常需要封装很多静态类、公共类的原因,但对于Java程序员来说这不是一件很正常的事情吗?就像吃饭要用筷子夹,喝汤要用勺子舀一样。而AOP的思想却是关注横向切面,相当于在纵向关系链中横切一刀,将那些业务模块的公共调用代码封装起来,形成一个切面(Aspect),从而减少了公共代码的引用点,提高了可维护性。下图是小编绘制的一副AOP与OOP关系的小图:
很多小伙伴问AOP适合应用于什么样的场景?关于这个问题,网上有回答大部分都是
权限认证、日志、事务、监控
等场景,其实在小编看来,AOP是一种横向关注思想,可以说是一种基本的开发技巧,并不局限于某些特定的应用场景,只要在系统中,从横向角度可以看到有代码优化与简洁的空间,那就能用AOP技术来改善代码。这里小编始终在强调两个字:横向
!的确,AOP开发最重要的指导思想就是角度,而最重要的观察角度就是横向(就像上图中小编画的程序员的眼睛那样观察)。关于AOP的理解,忆蓉之心说他一直把AOP看做”刀与豆腐的关系,哪里不爽,就切一刀“,的确这种横切一刀很形象的表达了AOP两个重要元素:横向与切面。其实过滤器技术(filter)即可看成面向切面的一种开发思想,只是过滤器一般应用于特定场景,不具备通用性。本片小编带大家一起探讨一下Spring 中对于AOP的通用支持 -- Spring AOP。
Spring AOP
Java中AOP的实现分为了基于AspectJ实现的静态织入
与Spring支持的动态代理织入技术
。ApectJ的原理主要是通过控制Java的编译时机,将切面增强代码直接编译入生成的class文件中,其效率较高,但入侵性强。而Spring AOP的动态织入主要依赖于JDK动态代理
与CGLIB的动态代理
来实现,相对于ApectJ绿色环保,但效率相对较低。(关于动态与静态的具体原理,以及一些剖析将在下一篇中详细讨论,本文主要让小伙伴们先初步认识一下Spring AOP的使用方式)。在项目中引用Spirng AOP也非常方便,通过Maven就可以简单的引入Spring AOP依赖的包了:
OK现在,我们就可以开始使用AOP来在项目中进行切面开发了。但是在开发前,需要理解一下AOP开发中的一些流程。其实引入Spring后,AOP开发非常简单,程序员只需要根据具体的业务逻辑
定义切入点
,然后程序员就只需要关注该切入点的增强处理逻辑(Advice)开发工作即可,然后剩余的工作就都交给AOP框架去自动实现了,Spring AOP框架会根据代理的切入点定义自动生成代理对象,而代理对象的方法便是增强处理加上被代理(目标)对象的方法的“总和”。AOP织入后,代理类与被代理类的关系可以抽象如下图所示的关系:image.png
其实,AOP技术的思想与实现非常像作者之前从事C++开发中用到的Hook技术,其本质都通过对目标对象的代理,从而达到对目标对象调用的监控与扩展,只是实现的具体技术与方式有些区别罢了。所以在开发这个领域来说,很多技术都是相通的,多领会一门语言技巧,或许会为你多增加一个看待编程的角度
Spring AOP的使用
好了,这里我们就可以开始使用Spring AOP来进行切面开发了,首先我们准备一个用于测试的服务类接口与服务实现,如下:
万事俱备,我们可以定义一个用于监控Service包下所有函数调用的监控切面,这里我们使用前置增强(Before)来实现对应的功能。代码如下:
image.png
好了,此时,我们就对 service包下的所有类的,所有函数调用进行了前置增强,在增强逻辑中我们只简单打印出增强的函数名称,运行结果如下:
image.png
上一节我们已经开发了前置增强处理,实际上Spring几乎支持了函数级别调用的所有环节的增强处理,常用的增强处理有
@Before
、@After
、@Around
、@AfterReturning
、@AfterThrowing
这5种增强,分别对应于被代理目标函数调用的 前置、后置、返回、异常返回、包含 这5种增强处理模式,这5种增强处理为AOP开发提供了全面的切入时机的支持,并且使用方式也非常统一,与上节Before增强的编写几乎相同:image.png
AOP的切入点
从上节开始,小伙伴基本上就能利用Spring AOP进行切面开发了。但是一定存在疑问,为何所有注解中都声明了这样的语句,如下:
execution(*com.znlover.spring.aop.sample.service.*.*(..))
这是什么鬼,这是AOP切入点的表达式语句,而Spring AOP表达式语句是从静态织入AOP框架ApectJ
的表达式语法继承来的(完全相同)。具体全面的语法规则,小伙伴可以查阅相关资料,这里我们解读一下最常用的execution表达式语法,如下图所示:
此外,Spring AOP 还支持通过@Pointcut定义一个通用的切入点,这样就可以在其他增强注解中以名称的方式使用该切入点,从而避免了多出重复编写表达式语句:
image.png
网友评论