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 ...
随机推荐
- vue-品牌管理案例
品牌管理 分析 获取到 id 和 name ,直接从 data 上面获取 组织出一个对象 把这个对象,调用 数组的 相关方法,添加到 当前 data 上的 list 中 注意:在Vue中,已经实现了数 ...
- android studio 菜单中的app运行按钮上有个叉号,原因与解决办法(自己去百度)
http://blog.csdn.net/sz0268/article/details/51706397 : 在Android studio写代码中,直接建立项目,写代码然后运行是不会一般是不会出现这 ...
- LinuxShell脚本——认识Shell脚本
LinuxShell脚本——认识Shell脚本 摘要:本文主要介绍了Shell脚本的一些基本知识. 什么是Shell脚本 shell脚本是利用shell的功能所写的一个程序,这个程序是使用纯文本文件, ...
- 易优CMS:关于assign你知道多少
[基础用法] 名称:assign 功能:模板文件中定义变量,可在其他标签里使用该变量 语法: {eyou:assign name='typeid' value='5' /} 文件: 无 参数: nam ...
- selenium 优化 提升性能
结果: 用时:7.200437545776367s用时:5.909301519393921s headless用时:4.924464702606201s headless\phone用时:4.9358 ...
- kafka集群在消息消费出现无法找到topic分区的处理解决
最近几天在做spark数据同步过程中,中间通过kafka集群处理消息,每次同步到一半就会出现同步不了 查看日志如下: 最开始看到这个问题很懵逼,完全找不到解决问题的切入口,期间也询问了架构师-因为这个 ...
- Promise简单使用,需要在ES6以上
//Promise延时顺序执行 var waitOne = new Promise(function(resolve, reject) { setTimeout(function(){ resolv ...
- 简易用户管理系统-前端实现(表单&提交请求&button$基础)
laravel框架编写简易用户管理系统,前端Layui框架. 1.动态生成列表项 实现效果 PHP后台传入用户对象($users). 前端页面接收数据传入table. 逻辑就是在生成表格时,遍历传来的 ...
- DataGuard搭建逻辑StandBy
DataGuard搭建逻辑StandBy 原创 作者:bayaim 时间:2016-03-31 17:23:48 272 0删除编辑 物理StandBy优点是效率高,缺点是只读模式不能恢复,恢复模 ...
- 第15讲:嵌入式SQL语句(动态SQL)
一.动态SQL概述 1. 静态SQL vs 动态SQL ①动态SQL是相对静态SQL而言的 ②静态SQL特点:SQL语句在程序中已经按要求写好,只需要把一些参数通过变量传递给SQL语句即可 specN ...