面向切面编程(AOP)跟面向对象编程(OOP)一样,是现代软件工程的精炼理念,但你认为它们有什么区别吗?如果把面向对象编程比喻成一块奶酪,那么面向切面编程就像是奶酪刀-- 理想地用来“切”开软件的复杂性。
OOP将我们的代码按业务的不同划分,而AOP则解决横向重复的技术难题。例如,私密信息加密、操作日志记录、开发阶段的性能测试——这些都是我们程序中重复出现的元素,他们就像酱汁里溢淌出来的调料,让我们一度失去对代码的控制。
可以想象,如果需要给系统中的每个业务方法的执行增加特定的方法调用日志输出,如何做? 增加调用耗时,如何做?如果你是在每个方法中都写入相应的方法调用日志输出,如果你是在每个方法内计算执行耗时,恭喜你,你是勤奋而优秀的挖坑人。
AOP,正是把这些重复的元素聪明地"切"下来,让你的代码更加整洁,可以做到在不改动这些原始方法的基础上,针对特定的方法进行功能的增强(可以在方法执行前,执行后,执行过程进行增强)。Spring给我们提供了AOP的利器,让我们的代码像新鲜出炉的面包一样,整洁又美味。
接下来让我们一探AOP的奥秘。首先,我们要将奶酪“切”成适应不同口味的部分,AOP里的’"切点"就扮演着这样的角色。切点决定了何时执行何种操作,类似于在面包上抹上哪种酱料。
然后我们有了"切面",这是我们用来添加新的行为的部分。类似于,在面包上加上芝士或者火腿,为面包增添风味。
AOP英文全称:Aspect Oriented Programming(面向切面编程、面向方面编程),其实说白了,面向切面编程就是面向特定方法编程。
AOP的作用:在程序运行期间在不修改源代码的基础上对已有方法进行增强(无侵入性: 解耦)
学习和使用AOP,不得不了解的几个核心概念如下:
连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
连接点指的是可以被aop控制的方法。例如:入门程序当中所有的业务方法都是可以被aop控制的方法。 比如我们要对哪些业务方法进行耗时统计,具体每一个业务方法就是连接点。
通知:Advice,指要执行的重复的逻辑,也就是共性功能;
切入点:PointCut,匹配连接点的条件,仅对切入点方法执行时相应的增加,切入点一般是通过具体的表达式通配出来的;
切面:Aspect,描述通知与切入点的对应关系(通知+切入点),在切入点执行对应的通知功能,从而避免重复繁琐。
目标对象:Target,通知所应用的对象,目标对象指的就是通知所应用的对象(即具体业务方法所在的类在当前线程中的实例对象),我们就称之为目标对象。
最后,我们的"增强"是切片的结果,是我们已经选择好的面包、酱料和配料的最终呈现。就像完成的三明治工艺品,你可以按自己的口味去享受了!
在Spring中,我们有多种方式对AOP进行配置,最常见的就是基于注解或基于XML的配置方式。如果说面向切面编程是从厨房的效率中寻找主题,那么,XML就像是预设的食谱,而注解方式更像是厨师自己的创新。前者规范又严谨,后者灵活又便捷。无论怎么样,我们都可以根据自己的需求去选择最适合我们的配置方式,实际业务开发中,最常用的方式就是灵活又便捷的基于注解的方式,本节将以基于注解的方式进行演示程序的开发,关于XML配置的方式,可以参见官网说明,Schema-based AOP Support
实际上,一个环绕通知就可以完成所有类型的通知,存在各种类型的通知,一定程度上是为了代码清晰,可读性强。(第二个方法注解是 @After,截图前写错了,见谅)
通过调试,我们可以更清晰的看到了执行的过程,那么在测试时,注入的PersonService已经不是纯洁的PersonService,而是在运行期被aop加解的类的对象,实际上就是代理对象,也就是说,对于我们切面作用到的业务类,通过spring容易获取对象时,获取到的是一个代理对象,除了具备原对象本身的业务方法,还对方法进行了加强,可能在方法执行前,执行后,或者环绕方法执行处进行了增加,至于具体是如何做到的,我们下章节给大家详细讲述。
为了更精细化的对某些指定的方法进行切入,我们切面还可以针对某些注解进行切入,从而实现对指定方法进行增强。
通过这样的方式,我们可以方便的给特定的方法加上要处理的逻辑,而不需要去修改原有的业务代码,真正做到了关注点的分离,这就是Spring AOP的强大之处。
关于AOP在Spring中的使用更详细系统性的教程,请参考官方文档,Spring AOP手册。