轻轻松松看懂Spring AOP源码
轻轻松松看懂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源码相关推荐
- 一文搞懂Spring AOP源码底层原理
一.什么是AOP 与OOP对比,AOP是处理一些横切性问题,这些横切性问题不会影响到主逻辑实现的,但是会散落到代码的各个部分,难以维护.一键获取源码地址spring aop面试题 AOP就是把这些问题 ...
- 76 张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖!
下面我会简单介绍一下 AOP 的基础知识,以及使用方法,然后直接对源码进行拆解. 不 BB,上文章目录. 1. 基础知识 1.1 什么是 AOP ? AOP 的全称是 "Aspect Ori ...
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- Spring AOP 源码分析 - 创建代理对象
1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...
- Spring AOP 源码分析 - 筛选合适的通知器
1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...
- dubbo 支持服务降级吗_dubbo面试题!会这些,说明你真正看懂了dubbo源码
整理了一些dubbo可能会被面试的面试题,感觉非常不错.如果你基本能回答说明你看懂了dubbo源码,对dubbo了解的足够全面.你可以尝试看能不能回答下.我们一起看下有哪些问题吧? dubbo中&qu ...
- 【Spring】Spring AOP源码分析-导读(一)
文章目录 1.简介 2.AOP 原理 3.AOP 术语及相应的实现 3.1 连接点 - Joinpoint 3.2 切点 - Pointcut 3.3 通知 - Advice 3.4 切面 - Asp ...
- Spring AOP 源码系列(一)解析 AOP 配置信息
在进行源码阅读之前建议先看一下这篇文章:Spring AOP 源码分析系列文章导读 by 田小波,写的非常好,推荐阅读. 关于 AOP 中常用的一些术语这里就不解释了,如果不清楚的建议先看一遍上面推荐 ...
- spring AOP源码分析(一)
spring AOP源码分析(一) 对于springAOP的源码分析,我打算分三部分来讲解:1.配置文件的解析,解析为BeanDefination和其他信息然后注册到BeanFactory中:2.为目 ...
最新文章
- 使用母版页后出现控件,使用FindControl找不到指定控件
- VS2010中添加第三方库目录VC++ Directories
- 北斗导航 | 监测和减轻空间天气对GNSS应用的影响
- Java字符串分割到map_如何在Java中按空格分割字符串并以键值形式存储在map中?...
- 用户授信额度管理中,会运用到哪些策略?
- usb设备的probe全过程
- 在Mac下安装nvm管理node
- 保存自动修复_模糊照片修清晰,使用自动修复软件,做出专业级老照片修复效果...
- 关于jstl EL用法的注意点(java.lang.NumberFormatException: For input string: userName)
- POJ 1190 生日蛋糕 DFS
- 数据库设计的几个建议
- fork函数原型与用法
- 微信支付之Native扫码支付功能
- WSL (Windows Subsystem for Linux) wsl1+wsl2+对比+在线安装+离线安装+版本转换+右键菜单+外网访问
- 医学图像配准中的深度学习综述论文解读
- 不想周末被工作提醒打扰?你需要这个手机便签消息免打扰设置
- 【机器学习中的数学】基函数与函数空间
- 阿里云的服务器,网站域名没有备案时为什么不可以访问?
- Fluent多相流之VOF模型操作实例
- 芯科发布EFR32BG22芯片,强劲性能对比TI芯片CC2640R2F和CC2640R2L