轻轻松松看懂Spring AOP源码

https://baijiahao.baidu.com/s?id=1596466083334197175&wfr=spider&for=pc

如果对spring的核心容器和JDK动态代理、CGLIB有所了解,接下来再看spring AOP源码会比较容易。文中所有代码片段截图对应的spring版本是5.0。

本文内容曾首发于头条。

首先来看个问题,spring在哪里使用了AOP?spring 实现AOP代码的源头在哪里?

spring AOP运用动态代理技术来创建和初始化代理对象。至于AOP代码的源头和入口,自然是和加载代理类的BeanDefinition和代理对象的创建、初始化有关。

1.spring AOP之加载和解析aop配置

先来看下加载BeanDefinition以及对aop配置的解析,下面是从容器开始启动到解析BeanDefinitions的方法链:

然后我们直接定位到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions,如下图:

上图中parseCustomElement是对非节点的解析,相关的节点解析自然是走178行代码分支。该分支实际调用的是下图中的代码片段:

1361行代码根据nameSpace匹配相应的handler,aop节点匹配的是右图中的AopNamespaceHandler。1366行的parse调用的是其父类NamespaceHandlerSupport的parse方法,如下图:

节点匹配的则是图中右侧的ConfigBeanDefinitionParser。来看下其实现:

上述代码106行配置了用于创建代理对象的AspectJAwareAdvisorAutoProxyCreator,我们看完aop配置解析之后再来分析。

节点的子节点是,所以这里走118行的分支。然后就是对的子节点,等的解析。

读到这里应该对AOP配置的解析有了大概的认识。但是你是否想过,解析的结果封装在哪里了?是ParserContext。

ConfigBeanDefinitionParser#parseAspect调用了ConfigBeanDefinitionParser#parseAdvice,来看下其实现:

其中340行是最关键的,可以看到最终是通过创建RootBeanDefinition来封装我们aop节点的配置信息,然后在349行将beanDefinition注册到容器(BeanFactory)。

aop配置的解析就看到这里。下面来看aop中代理对象的创建、实例化等。

2.spring AOP之创建代理

aop创建代理对象的时机是在调用getBean首次从容器中获取bean时。其实现

AbstractBeanFactory#getBean(java.lang.String)调用的是AbstractBeanFactory#doGetBean,下面来看该方法:

假设我们要获取的bean是单例并且是首次获取,那么真正创建bean是调用的312行的createBean方法。至此,我们来看一下整个方法链:

下面来看下AbstractAutowireCapableBeanFactory#initializeBean:

其中红线框起来的四个方法分别是:

invokeAwareMethods:调用BeanNameAware.setBeanName, BeanFactoryAware.setBeanFactory等

applyBeanPostProcessorsBeforeInitialization:调用BeanPostProcessor.postProcessBeforeInitialization

invokeInitMethods:调用InitializingBean#afterPropertiesSet,调用自定义initMethod

applyBeanPostProcessorsAfterInitialization:调用BeanPostProcessor#postProcessAfterInitialization

之前提到在解析aop配置时向容器注册了AspectJAwareAdvisorAutoProxyCreator,那么此处这个类要派上用场了。我们先来看下这个类的继承体系:

从顶层看,该类主要包含三部分:

ProxyConfig即解析而来的aop配置

Aware部分主要是使其可访问ClassLoader和BeanFactory

BeanPostProcessor则是bean初始化的前置和后置

上面出现的applyBeanPostProcessorsAfterInitialization调用的就是AspectJAwareAdvisorAutoProxyCreator的postProcessAfterInitialization,准确地说是其继承自父类的父类

AbstractAutoProxyCreator.postProcessAfterInitialization。我们来看下该方法调用的

AbstractAutoProxyCreator#wrapIfNecessary,这也是spring判断是否需要创建代理对象的地方:

该方法主要分三步:

352行判断该接口或类或方法是否与配置的pointcut的表达式匹配,匹配则需要创建代理对象,不匹配则无需代理。然后如果匹配则返回方法拦截器

355行创建代理对象

357行对代理类进行缓存

我们重点看下createProxy方法实现,方法链如下:

有了方法链之后我们直接跳到DefaultAopProxyFactory#createAopProxy,这个方法决定了spring aop动态代理是使用CGLIB还是JDK Proxy:

解释下51行if语句中的三个条件:

isOptimize表示让spring自行优化,默认为false

isProxyTargetClass表示是否对类生成代理,默认为false(即使用JDK Proxy,只代理接口)

第三个表示bean没有实现任何接口或者实现的接口是SpringProxy接口

综上,spring AOP默认的创建代理的策略是:

对接口生成代理使用JDK Proxy

对类生成代理使用CGLIB

可通过proxyTargetClass配置是否对类生成代理,为true表示对类生成代理,为false表示不会对类(没有实现SpringProxy以外的接口的类)生成代理

如果觉得写的不错,记得,如果写的不好欢迎批评指正,让我们一起进步!

转载于:https://www.cnblogs.com/handsome1013/p/11572845.html

轻轻松松看懂Spring AOP源码相关推荐

  1. 一文搞懂Spring AOP源码底层原理

    一.什么是AOP 与OOP对比,AOP是处理一些横切性问题,这些横切性问题不会影响到主逻辑实现的,但是会散落到代码的各个部分,难以维护.一键获取源码地址spring aop面试题 AOP就是把这些问题 ...

  2. 76 张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖!

    下面我会简单介绍一下 AOP 的基础知识,以及使用方法,然后直接对源码进行拆解. 不 BB,上文章目录. 1. 基础知识 1.1 什么是 AOP ? AOP 的全称是 "Aspect Ori ...

  3. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  4. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  5. Spring AOP 源码分析 - 筛选合适的通知器

    1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...

  6. dubbo 支持服务降级吗_dubbo面试题!会这些,说明你真正看懂了dubbo源码

    整理了一些dubbo可能会被面试的面试题,感觉非常不错.如果你基本能回答说明你看懂了dubbo源码,对dubbo了解的足够全面.你可以尝试看能不能回答下.我们一起看下有哪些问题吧? dubbo中&qu ...

  7. 【Spring】Spring AOP源码分析-导读(一)

    文章目录 1.简介 2.AOP 原理 3.AOP 术语及相应的实现 3.1 连接点 - Joinpoint 3.2 切点 - Pointcut 3.3 通知 - Advice 3.4 切面 - Asp ...

  8. Spring AOP 源码系列(一)解析 AOP 配置信息

    在进行源码阅读之前建议先看一下这篇文章:Spring AOP 源码分析系列文章导读 by 田小波,写的非常好,推荐阅读. 关于 AOP 中常用的一些术语这里就不解释了,如果不清楚的建议先看一遍上面推荐 ...

  9. spring AOP源码分析(一)

    spring AOP源码分析(一) 对于springAOP的源码分析,我打算分三部分来讲解:1.配置文件的解析,解析为BeanDefination和其他信息然后注册到BeanFactory中:2.为目 ...

最新文章

  1. 使用母版页后出现控件,使用FindControl找不到指定控件
  2. VS2010中添加第三方库目录VC++ Directories
  3. 北斗导航 | 监测和减轻空间天气对GNSS应用的影响
  4. Java字符串分割到map_如何在Java中按空格分割字符串并以键值形式存储在map中?...
  5. 用户授信额度管理中,会运用到哪些策略?
  6. usb设备的probe全过程
  7. 在Mac下安装nvm管理node
  8. 保存自动修复_模糊照片修清晰,使用自动修复软件,做出专业级老照片修复效果...
  9. 关于jstl EL用法的注意点(java.lang.NumberFormatException: For input string: userName)
  10. POJ 1190 生日蛋糕 DFS
  11. 数据库设计的几个建议
  12. fork函数原型与用法
  13. 微信支付之Native扫码支付功能
  14. WSL (Windows Subsystem for Linux) wsl1+wsl2+对比+在线安装+离线安装+版本转换+右键菜单+外网访问
  15. 医学图像配准中的深度学习综述论文解读
  16. 不想周末被工作提醒打扰?你需要这个手机便签消息免打扰设置
  17. 【机器学习中的数学】基函数与函数空间
  18. 阿里云的服务器,网站域名没有备案时为什么不可以访问?
  19. Fluent多相流之VOF模型操作实例
  20. 芯科发布EFR32BG22芯片,强劲性能对比TI芯片CC2640R2F和CC2640R2L

热门文章

  1. IE8兼容性问题的解决方案
  2. ORM进阶之Hibernate 的三大对象
  3. 配置防火墙打开 80 端口
  4. 一个简单的单例模式的类
  5. jquery select change事件_jQuery实现省市联动效果
  6. Matlab 画图字体,字号的设定,图片大小和比例
  7. java impliments,dubbo使用GenericService泛化调用
  8. vlookup练习_大胆合并吧!VLOOKUP坐字法专做单元格合并查找
  9. vue 子父组件周期顺序_父组件和子组件生命周期钩子执行顺序是什么?
  10. 知道这些性能优化手段,工资起码提升一倍