当前位置: 首页 > news >正文

Spring AOP源码分析

#### AOP(面向切面编程)作用及其优势
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强(通知)
优势:减少重复代码,提高代码复用性,提高代码可维护性,提高代码可扩展性
#### AOP的底层实现原理
动态代理:JDK动态代理 【基于接口的动态代理技术】(基于反射)、CGLIB动态代理【基于父类的动态代理技术】
实际上,AOP的底层是通过Spring提供的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态生成代理对象,代理对象方法执行时进行增强功能(通知)的介入,再去调用目标对象的方法(系统功能),从而完成功能的增强。
+ JDK动态代理:要实现InvocationHandler接口(java.lang.reflect.InvocationHandler),重写invoke方法,通过Proxy.newProxyInstance()方法创建代理对象。(反射)
+ Cglib动态代理:要实现MethodInterceptor接口(org.springframework.cglib.proxy.MethodInterceptor),重写intercept方法,通过Enhancer.create()方法创建代理对象
// 可以在启动时,设置保存生成的代理类文件
System.getProperties().put( "sun.misc.ProxyGenerator.saveGeneratedFiles" , "true" );
#### AOP的相关概念
+ Target:目标对象,被代理的对象
+ Proxy:代理对象,代理目标对象
+ Joinpoint:连接点,目标对象中可以被增强的方法
+ Pointcut:切入点,被增强的方法集合(对哪些Joinpoint进行拦截的定义)
+ Advice:通知,增强的代码(拦截到Joinpoint后要执行的代码)
+ Aspect:切面,切入点+通知
+ Weaving:织入,将通知应用到目标对象并创建代理对象的过程
#### AOP源码解析
1.须知:
-.在使用ApplicationContentext相关实现类加载ben的时候,会针对所有单例且非懒加载的bean,在构造ApplicationContext的时候就会创建好这些bean,而不会
等到使用的时候才会创建。这也就是单例bean默认非懒加载的应用。
-.读者需要了解BeanPostProcessor接口,这个接口是Spring提供的一个扩展接口,用于在bean初始化前后做一些处理工作。
- 结合以上两点,被代理后的bean,实际在ApplicationContext构造完成之后就已经被创建完成,getBean()的操作直接从singletonObjects中获取即可。
2. 注册自动代理创建器
- 但凡注解都有对应的解析器,以用来解析该注解的行为。而且所有的解析器父类为:NamespaceHandlerSupport,这个类是用来解析xml配置文件的。(可以通过调用链查看)
- 解析xml配置文件的时候,会调用NamespaceHandlerSupport的init()方法,这个方法会调用registerBeanDefinitionParser()方法,这个方法会将解析器注册到一个map中。
- Spring中将标签分为两大类:default(默认)和custom(拓展)
default namespace 涉及到的只有四个标签:import、alias、bean、beans  【使用方法parseDefaultElement(ele,delegate)】
custom namespace 涉及到的标签:mvc、task、context、aop等
- 以aop为例,解析器为AopNamespaceHandler,解析器会调用registerBeanDefinitionParser()方法,将解析器(AspectJAutoProxyBeanDefinitionParser)注册到一个map中。AspectJAutoProxyBeanDefinitionParser实现了BeanDefinitionParser接口,重写了parse()方法,这个方法会调用registerAutoProxyCreatorIfNecessary()方法【将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中,把bean交给spring去托管】
- 查看AnnotationAwareAspectJAutoProxyCreator的类层次结构,可知其父类为AbstractAutoProxyCreator,这个类实现了BeanPostProcessor接口,重写了postProcessAfterInitialization()方法(模板方法)
- 通过调用链查看,AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization()方法会调用wrapIfNecessary()方法,这个方法会调用createProxy()方法(将所有有Advice的bean重新包装成proxy)
3. 执行逻辑:代理对象创建好后,其拦截方法的操作都是交给Methodinvocation去做,JdkDynamicAopProxy交给ReflectiveMethodInvocation,ObjenesisCglibAopProxy交给CglibMethodInvocation.
类的继承关系(父->子)前面三个都是aopalliance下的
Joinpoint->Invocation->MethodInvocation(org.aopalliance.intercepet.MethodInvocation)->ProxyMethodInvocation->ReflectiveMethodInvocation->CglibMethodInvocation
这里说明一下JdkDunamicAopProxy的proceed()[继承自JoinPoint,执行链执行]方法
//这里是JdkDynamicAopProxy的执行的核心,要执行方法,执行通知都在这里搞定[递归调用,执行所有过滤器链的逻辑]
```
@Override
@Nullable
public Object proceed() throws Throwable {//this.currentInterceptorIndex初始值为-1,如果执行到执行链的末尾,则直接调用连接点方法(即目标方法)if(this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMathers,size() -1){//该方法内部逻辑调用目标方法return invokeJoinponit();}//获取集合中的MethodInterceptor,执行链索引加1(这里的+1保证是递归调用而不是循环调用)Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMathers.get(++this.currentInterceptorIndex);//InterceptorAndDynamicMethodMacher有两个属性MethodInterceptor,MethodMatcher,看看在advisor chain是否能够匹配上if(interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMacher){InterceptorAndDynamicMethodMacher dm = (InterceptorAndDynamicMethodMacher) interceptorOrInterceptionAdvice;//判断拦截器是否适用这个目标方法,是 执行这个拦截器 否 跳过这个拦截器进入下一个拦截器if(dm.methodMatcher.matches(this.method,this.targetClass,this.arguments)){//拦截器的内部,除自己逻辑外,也会有mi.proceed()保证执行到下一个拦截器return dm.interceptor.invoke(this);}else{return proceed();}}else {//MethodInterceptor直接执行(只有匹配上的方法才会在拦截器链中)return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);}
}
```

相关文章:

  • 基于MetaGPT构建LLM多智能体
  • c++ using 关键字
  • React 路由5版本的使用详解(基于Class类版本的使用react-router-dom@5)
  • 【编译原理复习笔记】中间语言
  • RK 11.0 多屏模式下修改鼠标进入方式
  • Web3 知识体系架构图
  • Shell编程规范与变量
  • VMware安装Windows11
  • ISCC——AI
  • getters的使用
  • uniapp开发微信小程序问题集锦(1)
  • Hadoop概览以及编译hadoop说明
  • SpringBoot高级原理详解
  • 【MyBatis】MyBatis解析全局配置文件源码详解
  • 深度神经网络详解
  • codis proxy处理流程
  • dva中组件的懒加载
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • GitUp, 你不可错过的秀外慧中的git工具
  • Java IO学习笔记一
  • Javascript基础之Array数组API
  • JavaScript设计模式与开发实践系列之策略模式
  • Java方法详解
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • Octave 入门
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 简单易用的leetcode开发测试工具(npm)
  • 来,膜拜下android roadmap,强大的执行力
  • 爬虫模拟登陆 SegmentFault
  • 如何设计一个微型分布式架构?
  • 深入浏览器事件循环的本质
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 自动记录MySQL慢查询快照脚本
  • 翻译 | The Principles of OOD 面向对象设计原则
  • 函数计算新功能-----支持C#函数
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • ​字​节​一​面​
  • #100天计划# 2013年9月29日
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #微信小程序:微信小程序常见的配置传旨
  • (16)Reactor的测试——响应式Spring的道法术器
  • (3)(3.5) 遥测无线电区域条例
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • *算法训练(leetcode)第四十七天 | 并查集理论基础、107. 寻找存在的路径
  • .babyk勒索病毒解析:恶意更新如何威胁您的数据安全
  • .FileZilla的使用和主动模式被动模式介绍
  • .net core webapi 大文件上传到wwwroot文件夹
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .Net FrameWork总结