Spring-AOP源码分析随手记(一)
1.@EnableAspectJAutoProxy(proxyTargetClass = true)
就是弄了个"org.springframework.aop.config.internalAutoProxyCreator"::AnnotationAwareAspectJAutoProxyCreator.class的Bean到容器中
2.分析AnnotationAwareAspectJAutoProxyCreator.class类结构
得出了哪些是重要的几个。
3.查看AnnotationAwareAspectJAutoProxyCreator源码
=》查看父类AbstractAutoProxyCreator,有setBeanFactory等等各种继承来的方法
4.又是一顿整理得出了一个图(???)如下
pic1->AOP功能代码分析图
5.分析AbstractAutoProxyCreator。
setBeanFactory有个O标志被重写了,打开,有个initBeanFactory方法,打开,创建了个advisorRetrievalHelper切面工具,又是O重写 创建了aspectJAdvisorsBuilder
6.pic1图里明显看出有两个关键性方法:
postProcessBeforeInstantiation和postProcessAfterInitialization
显然是前后处理逻辑了。肯定先看前逻辑postProcessBeforeInstantiation啊
7.postProcessBeforeInstantiation
断点走起,居然是从这里进去的
所以这个之前分析IOC的createBean里的resolveBeforeInstantiation是AOP实现的关键。
8.分析postProcessBeforeInstantiation细节
8.1 isInfrastructureClass判断是否基础Bean
就是那种AOP本身的比如Advice、Pointcut、AopInfrastructureBean等,基础的这种直接返回不需要代理
8.2 shouldSkip是否要跳过(包含找出切面)
8.2.1找出增强器(那种切面里的@After、@Before的方法)
跟随断点跳跃到之前setBeanFactory创建的advisorRetrievalHelper里去了帮忙实现的找增强器
实际上这里面又分两部分了,一个是找事务的(findCandidateAdvisors)(本次断点容器和缓存中都就没用了直接返回空,不是事务,具体可以看aop源码instan...图)
另一部分是this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
跳进去看了下,它把所有的beanname拿出来找,去找切面类 找到了我写的MyLogAspect
(打了切面切面注解)
然后找到了切面类,调用相关封装的getAdvisors方法去拿增强器了。
其实就是获取切面类的所有方法(getAdvisorMethods)把每个包含增强那些注解的方法包装成Advice 放进缓存。
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
而
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
然后
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
switch判断注解类型 创建不同类型Advice 放进缓存
最终由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()找到了我写的所有切面的增强方法
最终把整个切面类放到了advisorsCache的ConcurrentHashMap,以切面类的beanname作为key,增强器方法advice集合作为value
9.postProcessAfterInitialization
条件断点,当beanname = "calculate"时停住。找出增强器后,看看后续aop是怎么和目标类结合的。
10.postProcessAfterInitialization细节
断点已达。老办法,看看是从哪调来的:
原来是这里,ioc创建完对象并给属性赋完值之后。
回到postProcessAfterInitialization本身,就调了个wrapIfNecessary。逻辑都在里面了
10.1 找对应的增强器
打开断点继续,先主要是个getAdvicesAndAdvisorsForBean然后调findEligibleAdvisors然后就是以前跑过的找事务略。然后主要是findAdvisorsThatCanApply(名字也看得出,它能用的 这个bean对应的切面),进去又是个canApply(candidate, clazz, hasIntroductions),这就是具体判断了:
获取所有方法,用匹配器match去匹配是否匹配上了
循环记下,全部找出来,找增强器就结束了!
10.2 织入生成代理对象
回到wrapIfNecessary开始创建代理对象了:
这里面框起来是涉及注解配置的,对应你配置的:
@EnableAspectJAutoProxy(exposeProxy = true)
@EnableAspectJAutoProxy(proxyTargetClass = true)
如果这两个设置了的话,就会处理实现。
第二个是启动优先cglib,第一个是把代理对象创建好之后暴露出去,这样就能让原本this.dadd去调用方法本来不能增强的情况 可以用
((Calculate) AopContext.currentProxy()).add(numA,numB);也触发增强效果
后面的话就是创建个代理工厂ProxyFactory,把增强器设置进去,最后调用getProxy
一路跳转:
这就是最后网上背背背的东西了。在没有接口和没打优先cglib的话用jdk创建否则cglib创建。
问题:
1.怎么得出来继承结构哪些是重要的、哪些是不需要看不重要的
2.怎么整理出来的?
Spring-AOP源码分析随手记(一)的更多相关文章
- spring AOP源码分析(三)
在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib ...
- 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 筛选出 ...
- Spring AOP 源码分析系列文章导读
1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解.在写完 Spring IOC 容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了3天时间阅 ...
- Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理
AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...
- 5.2 Spring5源码--Spring AOP源码分析二
目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...
- 5.2 spring5源码--spring AOP源码分析二--切面的配置方式
目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...
- spring aop 源码分析(三) @Scope注解创建代理对象
一.源码环境的搭建: @Component @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON,proxyMode = ScopedP ...
- 最简 Spring AOP 源码分析!
前言 最近在研究 Spring 源码,Spring 最核心的功能就是 IOC 容器和 AOP.本文定位是以最简的方式,分析 Spring AOP 源码. 基本概念 上面的思维导图能够概括了 Sprin ...
随机推荐
- PlayJava Day004
今日所学: /* 2019.08.19开始学习,此为补档. */ JDK 1.6:byte , int , short , char , enum JDK 1.7:byte , int , short ...
- CAD总记不住?设计达人给你支招,最强口诀40条玩转设计
绘图界有这样一个准则:绘图越快,玩的越6 相反的,CAD玩的很6 ,你的绘图效率一定不会差到哪里去,虽然不能说的太绝对,但你就操作如果玩转,一定你就操作能给你的绘图带来很多效率的提升. 当然后面就你就 ...
- jsp表单数据添加到数据库
先由表单提交数据到某验证页面:checkregister.jsp<form method="POST"name="form1" action=" ...
- cesium-webpack 入门开发系列一初探篇(附源码下载)
前言 cesium-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 we ...
- xamarin Android 监听音量键(上)
public override bool OnKeyDown([GeneratedEnum]Android.Views.Keycode keyCode, KeyEvent e) { switch (k ...
- 成功安装mysql后,为何服务管理器里找不到MYSQL服务名【转】
解决方案:(参考以下命令) 1.打开cmd,切换到mysql的bin目录下 2. D:\Program Files\MySQL5.1\bin>mysqld.exe -install Servic ...
- Linux—系统关机命令详解
不管是重启系统还是关闭系统,首先要运行 sync 命令,把内存中的数据写到磁盘中.将数据由内存同步写入到硬盘中. [root@localhost ~]# sync 一.shutdown命令 # 立刻关 ...
- java链接集合
Intellij IDEA 导入eclipse web 项目详细操作 https://blog.csdn.net/deng11408205/article/details/79723213?utm_s ...
- 讲解web服务所涉及到的重要知识点
HTTP:超文本传输协议,默认为TCP的80端口.带有超级链接的文本,而这些链接成为超链接! loadrunner :专业级测试工具,模拟你的应用程序的真实,进行评测! HTML:超文本编辑语言. H ...
- golang数据结构和算法之BinarySearch二分查找法
基础语法差不多了, 就需要系统的撸一下数据结构和算法了. 没找到合适的书, 就参考github项目: https://github.com/floyernick/Data-Structures-and ...