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源码分析随手记(一)的更多相关文章

  1. spring AOP源码分析(三)

    在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib ...

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

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

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

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

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

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

  5. Spring AOP 源码分析系列文章导读

    1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解.在写完 Spring IOC 容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了3天时间阅 ...

  6. Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理

    AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...

  7. 5.2 Spring5源码--Spring AOP源码分析二

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

  8. 5.2 spring5源码--spring AOP源码分析二--切面的配置方式

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

  9. spring aop 源码分析(三) @Scope注解创建代理对象

    一.源码环境的搭建: @Component @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON,proxyMode = ScopedP ...

  10. 最简 Spring AOP 源码分析!

    前言 最近在研究 Spring 源码,Spring 最核心的功能就是 IOC 容器和 AOP.本文定位是以最简的方式,分析 Spring AOP 源码. 基本概念 上面的思维导图能够概括了 Sprin ...

随机推荐

  1. 易优CMS:小白学代码之notempty

    [基础用法] 名称:notempty 功能:判断某个变量是否为空,可以嵌套到任何标签里面使用,比如:channel.type等 语法: {eyou:notempty name='$eyou.field ...

  2. 简单两行,实现无线WiFi共享上网,手机抓包再也不用愁了

    你是否为WiFi共享而发愁,各个无线共享软件,某某共享精灵,某某免费WiFi,某某共享大师,某某随身WiFi,一个比一个难用,一个比一个私货多,一个比一个广告多,如果装上了它们,你的电脑就基本沦陷了, ...

  3. webUploader上传大视频文件相关web.config配置

    在webuploader上传大文件时必须配置一下,不然请求后台处理程序时,会请求超时.出现404! <system.web> <httpRuntime maxRequestLengt ...

  4. Android之okhttp实现socket通讯(非原创)

    文章大纲 一.okhttp基础介绍二.socket通讯代码实战三.项目源码下载四.参考文章   一.okhttp基础介绍 https://www.jianshu.com/p/e3291b7808e7 ...

  5. 每天一点产品思考(5):Web端链接跳转在当前页面刷新还是新标签页打开?

    一.与交互设计师的突然撕逼         今天阿白在验收产品的时候,在博客首页打开一篇博文,是在原先的页面进行刷新,而不是新开一个标签页打开.阿白让开发改成在新标签页中打开,但是开发说这是设计师设计 ...

  6. 微服务:Eureka+Zuul+Ribbon+Feign+Hystrix构建微服务架构

    原文地址:http://blog.csdn.net/qq_18675693/article/details/53282031 本案例将打架一个微服务框架,参考来源官方参考文档 微服务:是什么?网上有一 ...

  7. idea中git标签(tag)的创建与使用

    1.什么是标签 通常,发布一个版本时,会在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本.将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来. 所以,标签也是 ...

  8. Python中 if __name__ == '__main__' 的作用

    Python文件可以直接运行,也可以 import 到其它文件中使用 if __name__ == '__main__' 就是控制代码在这两种情况下的执行过程 每个Python模块都包含内置变量,直接 ...

  9. [Linux] 纯净ubuntu系统仓库更换为阿里云的源

    1.先apt-get update一下当前默认的源,更新完成后先把vim命令安装一下,再修改源仓库为阿里云,否则无法直接编辑文件 2.先添加阿里云的源,编辑文件/etc/apt/sources.lis ...

  10. 有用的link

    资料 了解oi 刘汝佳代码仓库(紫书 c++参考手册 2018年洛谷日报索引 2019年洛谷日报索引 (其他oj: luogu 虚拟判官(名校oj都有 离线bzoj题库 (有时候进不去请点:rxz大爷 ...