一直想抽空把Spring源码拿来读读,但真正去做这件事的时候发现不简单,Spring发展这么多年,它的规模已不是一个一般的开源框架所能比的,它的主要架构和流程不是非常清晰,很难抓到要害,但有一点可以肯定,它的根基是IoC和AOP,所有的功能扩展和对其他开源框架的支持都是基于这两点来做的,因此要搞定Spring源码主要就是要搞定IoC和AOP这两块。

IoC从原理上来说是非常简单的,无非就是从配置文件解析开始到最后在内置容器中管理各个对象,但从Spring IoC源码上看是个非常庞大的体系,因为Spring能支持的特性太多,针对这一点,我已不太可能仔细地阅读每一个细节,也不太可能通过什么方式把这些细节在有限的篇幅中表达出来,只能抓住关键生命周期中关键步骤。

在我看来,IoC最核心就是两个过程:IoC容器初始化和IoC依赖注入,下面通过简单的图示来表述其中的关键过程。

Spring源码学习(二)------ AOP

AOP有些特有的概念,如:advisor、advice和pointcut等等,使用或配置起来有点绕,让人感觉有些距离感,其实它的实现就是一组标准的设计模式的组合使用:Factory、Proxy、Chain of Responsibility,只要搞清楚这几个设计模式,读AOP的源码是比较容易的。

首先看看ProxyFactoryBean这个类,这是AOP使用的入口,从AOP拿到的bean object就是ProxyFactoryBean.getObject得到的,从这条线下去,发现AOP就是通过Proxy模式从实际要执行的target做了包装,而Proxy还不止一套方案,通过Factory封装了两套Proxy实现方案:JDK 动态Proxy和Cglib Proxy。有两套实现主要是因为JDK 动态Proxy必须要target实现某个接口,如果不满足这个条件就会用Cglib增强字节码的方式来实现proxy。

就拿JDK Proxy为例,Spring AOP使用了标准的JDK提供的动态Proxy方案,我们先看看标准的动态Proxy是什么样子,看下面类图:

Cilent通过Proxy.newProxyInstance(classLoader, proxiedInterfaces, invocationHandler);就能拿到target的proxy object,在执行target的方法时就会先执行到DynamicProxy中的invoke方法从而实现代理包装。基于这个道理来看Spring
AOP的实现,实际上就是标准地基于这个方式来做的,Spring AOP的所有花招都体现在JdkDynamicAopProxy.invoke中(当然在Cglib中是通过callback来做的,道理类似)。

通过看JdkDynamicAopProxy.invoke的源码会发现,Spring AOP的各种花招是通过Chain of Responsibility模式串起来的,先看看一个标准的Chain
of Responsibility是什么样子,看下面的类图:

而Chain of Responsibility的关键在于Invocation与Interceptor的配合,主要原则就两条:

1)Invocation需要维护Interceptor集合和游标,每次调用invoke时需要先调用游标所在的Interceptor.invoke,如果游标已超过最后一个Interceptor,则调用实际target的方法

2)Interceptor的invoke中除了要执行自己的拦截逻辑,还要通过Invocation.invoke把调用传递下去,拦截的灵活性就体现在Invocation.invoke执行与否和执行的顺序。

以上逻辑通过时序图来看,如下图所示:

理解Chain of Responsibility后再来看Spring AOP,JdkDynamicAopProxy.invoke做的事情就是以上Client做的事情,

1)首先通过this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);组装interceptor chain

2)然后new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);得到invocation

3)最后通过invocation.proceed();启动责任链

advice

英 [əd'vaɪs] 美 [əd'vaɪs]
  • n. 建议;忠告;劝告;通知

advise

英 [əd'vaɪz] 美 [əd'vaɪz]
  • vt. 建议;劝告,忠告;通知;警告
  • vi. 建议;与…商量

而Spring AOP的那些概念都体现在组装interceptor chain中,advisor、advice和pointcut无非就是帮助你描述如何对Target进行拦截,对这一块感兴趣的朋友可以好好读读里面的代码。另外,Spring AOP提供了各种各样的Interceptor,来实现各种形式的横切,具体做法可以详细看看各Interceptor的实现。

综上所述,整个流程如下图所示:

总之,把握了Factory、Proxy、Chain of Responsibility的运用也就把握了Spring AOP的实现原理,道理虽然简单,但其中的精髓和原由还是值得我们继续深思的。

Spring源码学习 ------ IoC——AOP的更多相关文章

  1. spring源码学习之AOP(一)

    继续源码学习,看了spring中基础的容器和AOP感觉自己也没有什么长进,哈哈,我也不知道到底有用没有,这可能是培养自己的一种精神吧,不管那么多,继续学习!AOP中 AOP中几个重要的概念:(1)Ad ...

  2. spring源码学习之AOP(二)

    接着上一篇中的内容! 3.创建代理 在获取了所有的bean对应的增强器之后,便可以进行代理的创建了org.springframework.aop.framework.autoproxy包下的Abstr ...

  3. spring源码学习之路---深入AOP(终)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...

  4. spring源码学习之路---IOC初探(二)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...

  5. Spring 源码学习——Aop

    Spring 源码学习--Aop 什么是 AOP 以下是百度百科的解释:AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程通过预编译的方式和运行期动态代理实 ...

  6. Spring 源码学习笔记10——Spring AOP

    Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...

  7. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  8. Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

    写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...

  9. Spring 源码学习笔记11——Spring事务

    Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...

  10. spring源码浅析——IOC

    =========================================== 原文链接: spring源码浅析--IOC   转载请注明出处! ======================= ...

随机推荐

  1. mysql bit(1) 字段insert 报错 Data too long

    insert数据时,给bit(1)字段赋值 '1' 报错 将字符串'1',修改为数字1即可

  2. 效率跃升16倍!火山引擎ByteHouse助力销售数据平台复杂查询效率大幅提高

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群.   销售数据,是反映市场趋势.消费者行为以及产品表现的重要指标,也是企业做出精准决策的关键依据.因此,对销售数据 ...

  3. sql server 将数据库表里面的数据,转为insert语句,方便小批量转移数据

    create proc [dbo].[proc_insert] (@tablename varchar(256)) as begin set nocount on declare @sqlstr va ...

  4. .net 环境使用 RabbitMQ ,由浅入深 【一】

    最近因为先开发的项目需要用到消息队列,因此捣鼓了一下市面上开源的消息队列. 原本听闻Rocketmq ,一开始用的是 RocketMQ,各种集群搭建完毕,消息发送什么的测试后,,但是结果因为 Rock ...

  5. DTO转VO工具

    data工具,实现了对象拷贝 DTO -> VO 只需要实现一个类即可 data-utils data工具,实现了对象拷贝DTO -> VO 解决的问题 Mapstruct需要安插件!!! ...

  6. C++ STL(标准模版库)—— vector 与 迭代器

    STL 基本概念 STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称. STL 从广义上讲分为三类:algorithm(算法).containe ...

  7. 异步解析文件报错 NoSuchFileException

    问题描述:同步上传解析文件超时,修改为异步解析后找不到 文件 java.nio.file.NoSuchFileException 原因:异步文件上传,主线程结束后,临时目录的文件会被清理掉,子线程此时 ...

  8. 【赵渝强老师】Redis案例分析:用setbit统计活跃用户

    一.需求背景 首先,我们来看一下需求:网站统计用户登录的次数,具体如下: 网站有1亿个用户,有经常登录的,也有不经常登录的 如何来记录用户的登录信息 如何查询活跃用户:比如:一周内,登录3次的 二.使 ...

  9. IDEA更改远程git仓库地址

    前言 我们在使用IDEA开发时,一般会配置好对应的git仓库,这样就比较容易对代码进行控制以及协同开发.   但有时候,我们远程的仓库地址由于这样那样的原因,需要迁移(这在爱折腾的企业是常有的事情). ...

  10. 世界第一!华为云图引擎服务GES大幅刷新世界纪录

    近日,国际关联数据基准委员会(Linked Data Benchmark Council,以下简称LDBC)公布了社交网络测试交互式负载(SNB INTERACTIVE WORKLOAD,以下简称为S ...