从宏观角度分析Spring源码之AOP

   日期:2020-05-19     浏览:95    评论:0    
核心提示:众所周知,Spring容器的三大核心功能是IOC、DI和AOP,前面我们已经对IOC和DI的理论做了浅析,这篇文章将从AOP的概念、设计思路、应用场景、Spring AOP的源码分析四方面入手,理解下AOP究竟是个神马东东。1、概念AOP的英文全称是Aspect Oriented Programming,即面向切面编程。借鉴一下维基百科中对AOP相关概念的描述:Aspect是一种新的模块化机制,从关注点中分离出横切关注点是面向切面编程的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独java

众所周知,Spring容器的三大核心功能是IOC、DI和AOP,前面我们已经对IOC和DI的理论做了浅析,这篇文章将从AOP的概念、设计思路、应用场景、Spring AOP的源码分析四方面入手,理解下AOP究竟是个神马东东。

1、概念

AOP的英文全称是Aspect Oriented Programming,即面向切面编程。借鉴一下维基百科中对AOP相关概念的描述:

Aspect是一种新的模块化机制,从关注点中分离出横切关注点是面向切面编程的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。

简单点来说,程序中总会出现一些重复的代码,而且不太方便使用继承的方式来实现重用和管理,这些功能重复并且需要用在不同的地方,这时候AOP就可以派上用场了。

AOP中的几个重要名词:

Aspect:Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice,Spring常用注解@Aspect来标识这是一个切面。

Advice:通知,定义在连接点做什么,为切面增强提供织入接口,在Spring中,它主要描述Spring AOP围绕方法调用而注入的切面行为,提供了具体的通知类型,例如BeforeAdvice、AfterAdvice、ThrowsAdvice。

JoinPoint:连接点,定义一个通知在程序中执行的位置,可以是方法前、方法后、抛出异常时等。

PointCut:切点,确定Advice通知应该作用在哪个连接点上,通俗来讲就是通过PointCut来定义需要增强的方法的集合,这些方法集合的选取可以由正则表达式进行标识,或根据某个方法名进行匹配。

2、Spring中的设计

AOP是Spring的核心模块,虽然AspectJ是一个完整的AOP框架,但在Spring中提供了另外一种实现,这种实现并不是要和AspectJ做竞争,相反,Spring AOP还将AspectJ集成进来,为IOC容器和Spring应用的开发提供了一个一致性的AOP解决方案。

Spring AOP是以动态代理为基础,设计出来一系列的AOP横切实现,例如前置通知、后置通知、环绕通知、异常通知等。同时Spring还提供了Pointcut来匹配切入点,可以直接使用来设计横切面。

在Spring中是用AOP,只需要配置相关的Bean定义即可,但分析Spring AOP的源码可以看到,为了实现AOP的完整功能,Spring实现了一个很长的调用链来完成这个过程。

3、Spring AOP的应用场景

Spring AOP的应用场景有很多,我们在实际项目开发中经常用到的场景如下:

(1)日志记录

(2)事务

(3)权限

(4)缓存

4、Spring AOP源码分析

大家都知道,Spring AOP是以动态代理(JDK或CGLIB)为基础的,根据以往看源码的经验,我们继续从Spring AOP的源码中抽取一条具有代表性的主线进行分析,以JDK动态代理为例。

时序图:

在Spring抽取出的一条AOP的实现线路后,可以发现这个过程主要分为三步:创建代理类、代码织入、通知回调

(1)创建代理类

回顾Spring的依赖注入过程,在AbstractAutowireCapableBeanFactory类的doCreateBean方法中调用populateBean完成Bean的属性赋值,在populateBean方法后继续调用initializeBean方法对Bean进行初始化,实际上是在Bean的初始化前后添加了BeanPostProcessor后置处理器。源码如下:

 

生成代理类是在bean初始化之后,即调用applyBeanPostProcessorsAfterInitialization方法,再调用postProcessAfterInitialization方法,查看源码如下: 

进入wrapIfNecessary方法:

在 wrapIfNecessary方法中可以看到两个重要的步骤,即getAdvicesAndAdvisorsForBean和createProxy,getAdvicesAndAdvisorsForBean是获取bean的所有advice,createProxy是创建代理类的入口方法,源码截图中已给了注释,可自行翻阅源码。

点进createProxy方法中可以看到getProxy方法的两个实现类,Jdk动态代理和Cglib动态代理。如果bean实现的是接口则使用jdk动态代理,否则使用Cglib动态代理生成代理类。

 

(2)代码织入和通知回调

在JdkDynamicAopProxy类中,invoke方法是被代理对象方法调用的入口,getInterceptorsAndDynamicInterceptionAdvice方法返回一个连接器列表,如果这个列表chain不为空,就会创建一个ReflectiveMethodInvocation对象invocation,接下来调用invocation的proceed方法。

在 proceed方法中,会动态匹配joinPoint,如何匹配满足条件,调用拦截器的invoke方法,invoke方法有几个实现类,分别为AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAroundAdvice、AspectJAfterThrowingAdvice,对应着AOP中的前置通知、后置通知、环绕通知、异常通知等。

 

动态代理生成代理类,通过自定义的匹配规则匹配到方法对应的拦截器,这样对方法进行增强,完成了AOP方法的切入。

 

 

欢迎关注公众号进行技术交流,新开通的公众号,以后会分享java技术、源码、架构和面试题。

 

 

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服