源码剖析篇—Spring Aop

1 什么是AOP

关于AOP的相关概念解释网上一搜一箩筐,笔者不在这里赘述。本文主要介绍AOP的思想以及简要分析一下Spring AOP的核心代码。我们从生活中一个常见的例子开始。现在高铁网络很发达,高铁是很多人出行的首选之一。乘坐高铁有一个重要的环节是检票,在进入候车大厅时要交出身份证进行检票检查。有趣的地方就在这里,为什么要在候车大厅的门口进行检票呢?可能有的人觉得理所应当,这是受思维定势的影响,生活中习以为常的事就变得理所应当。我们抛开所有的过往经验,假设现在要建一座高铁站,你是总设计师,在设计检票这一环节时你会怎么做呢?不在候车大厅门口设置检票口行不行呢?让乘客们先进入候车大厅,然后再安排专门人员进行逐个检票,这样行不行呢?完全可以,但是现实的经验告诉我们,这样做会耗时耗力,随着乘客的不断增加,检票工作会变得异常复杂。
我们再回到代码设计上,道理是一样的,因为代码要解决的也是现实生活中的问题,把现实生活中我们习以为常的事物接入到互联网中。假设要对接口进行鉴权,你会怎么做呢?在每个接口里加上一个判断是否有调用该接口的权限?如果这么做就相当于上面的在候车大厅里检票的场景,耗时耗力、一堆重复代码、加重代码耦合度,随着业务的不断迭代,代码会变得臃肿不堪。这个时候就出现了一种思想,面向切面编程,即AOP。就像检票口一样,有一个统一的入口,在进入方法前进行拦截,拦截之后进行鉴权操作,鉴权通过后再放行进入方法。

2 动态代理

说到Spring AOP就不得不提动态代理,因为Spring AOP是基于动态代理来实现的。那什么是动态代理呢?笔者还是想通过现实生活中的例子来进行解释。假设你刚买了一套新房,你可能需要找个设计师来给你做室内设计,找个粉刷工师傅给你粉刷墙壁,找个水电工师傅给你装电路和水管,装修完之后你可能还需要找个保洁来给你打扫房间。你不仅需要和他们商谈价钱还要合理安排他们的上门服务时间,这就会耗费你大量的精力和时间。如果有个家装公司能提供一整套的服务,从设计到装修到保洁,每种服务都会给你提供专业的人员,你只需要把你的需求告知这家公司即可。你不需要做任何事情就能让你看到一个心满意足的房子。这就是动态代理的思想,家装公司是一个代理生产方,能提供不同的代理服务。Spring AOP就相当于这个家装公司,创建代理的工作全部交由Spring AOP来完成,在项目启动时,Spring AOP会创建好代理实例。

3 Spring AOP工作机制

在介绍工作机制之前我们先来思考一个问题,下图中myHouse和house所引用的实例有没有区别?如果有,那有什么区别?
在这里插入图片描述
假设在一个阳光明媚的早晨,你满怀期待的去看你崭新的房子,但是当你打开门时眼前的一幕是你内心迸发出的欣喜感顿时消失了。满地的灰尘,建房子时留下的残余物散散落落的遍布在房间里的各个角落。这个时候你才意识到你还没有叫家装服务,你还没有让家装公司来给你装修房子。用程序的思维来说就是没有给对象注册一个代理,一个能装修房子的代理。
在这里插入图片描述
如果Myhouse里有一个开门的方法,那么只能输出一个没有装修过的房间。所以通过Spring注入的实例与手工创建的实例是有区别的,Spring注入的是一个经过加工的增强实例,这个增强实例就是一个动态代理实例,Spring给这个增强实例添加了一些额外的属性和行为所以在调用myHouse.openDoor()放的时候,其实走的并不是MyHouse里的方法,而是动态代理类里的方法。这就是动态代理的高明之处,对你的代码没有任何的侵入性,在你没有任何感知的情况下帮你实现了你的需求。因此你就可以找一个代理来帮你装修房子,也就是我们通常见到的拦截器,此时在你打开门之后就能看到一个崭新的房间。

3.1 AopProxy容器

AopProxy容器提供了两种动态代理的实现机制
在这里插入图片描述
本文只介绍CglibAopProxy,CglibAopProxy不仅可以代理接口也可以代理类。代理实例是由ProxyFactory代理工厂来创建的。在bean初始化后会调用AbstractAdvisingBeanPostProcessor里的postProcessAfterInitialization方法
在这里插入图片描述
其中,isEligible判断是否要生成动态代理,如果项目中没有配置AOP是不会创建代理的。生成代理的核心逻辑在CglibAopProxy的getProxy方法里。
在这里插入图片描述
上图中:
1). Class<?> proxySuperClass = rootClass:将被代理的类作废代理类的父类;
2). Callback[] callbacks = getCallbacks(rootClass):获取回调函数,拦截规则以及方法的拦截链路执行都在Callback里实现;
3). createProxyClassAndInstance(enhancer, callbacks):生成代理类和创建代理实例。

在getCallbacks方法里可以看到一个比较重要的类DynamicAdvisedInterceptor,该类就是用来AOP回调的,也就是通过代理触发的方法都会
在这里插入图片描述
被该类里的intercept方法拦截。
在这里插入图片描述
在触发myHouse.openDoor()方法之前,会先进入到上图中的方法里,图中:
1). List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass):获取方法的拦截链,也就是给该方法添加的所有拦截器;
2). retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed():创建一个方法的invocation,并调用proceed()方法执行所有实现org.aopalliance.intercept.MethodInterceptor接口的拦截器,拦截器执行完之后会调用被代理类的myHouse.openDoor()方法并返回结果。

总结

以上对Spring AOP作了简要介绍,要理解AOP的思想还是要结合生活中的实际例子来理解。AOP思想在现实生活中并不是一种新事物,它新就新在运用在了程序设计上。没有一种事物是凭空想象出来的,一定是在前人总结的经验基础上作了改进而创造出一种新的事物。人类发展到现在总结出的宝贵经验怎么运用到程序设计上是一件非常值得去思考的事情。

猜你喜欢

转载自blog.csdn.net/weixin_45497155/article/details/105825388
今日推荐