springaop实现原理_spring AOP的实现原理
基于代理(Proxy)的AOP实现
首先,这是一种基于代理(Proxy)的实现方式。下面这张图很好地表达了这层关系:
这张图反映了参与到AOP过程中的几个关键组件(以@Before Advice为例):
- 调用者Beans - 即调用发起者,它只知道目标方法所在Bean,并不清楚代理以及Advice的存在
- 目标方法所在Bean - 被调用的目标方法
- 生成的代理 - 由Spring AOP为目标方法所在Bean生成的一个代理对象
- Advice - 切面的执行逻辑
它们之间的调用先后次序反映在上图的序号中:
- 调用者Bean尝试调用目标方法,但是被生成的代理截了胡
- 代理根据Advice的种类(本例中是@Before Advice),对Advice首先进行调用
- 代理调用目标方法
- 返回调用结果给调用者Bean(由代理返回,没有体现在图中)
为了理解清楚这张图的意思和代理在中间扮演的角色,不妨看看下面的代码:
@Componentpublic class SampleBean { public void advicedMethod() { } public void invokeAdvicedMethod() { advicedMethod(); }}@Aspect@Componentpublic class SampleAspect { @Before("execution(void advicedMethod())") public void logException() { System.out.println("Aspect被调用了"); }}sampleBean.invokeAdvicedMethod(); // 会打印出 "Aspect被调用了" 吗?
SampleBean扮演的就是目标方法所在Bean的角色,而SampleAspect扮演的则是Advice的角色。很显然,被AOP修饰过的方法是advicedMethod(),而非invokeAdvicedMethod()。然而,invokeAdvicedMethod()方法在内部调用了advicedMethod()。那么会打印出来Advice中的输出吗?
答案是不会。
如果想不通为什么会这样,不妨再去仔细看看上面的示意图。
这是在使用Spring AOP的时候可能会遇到的一个问题。类似这种间接调用不会触发Advice的原因在于调用发生在目标方法所在Bean的内部,和外面的代理对象可是没有半毛钱的关系哦。我们可以把这个代理想象成一个中介,只有它知道Advice的存在,调用者Bean和目标方法所在Bean知道彼此的存在,但是对于代理或者是Advice却是一无所知的。因此,没有通过代理的调用是绝无可能触发Advice的逻辑的。如下图所示:
Spring AOP的两种实现方式
Spring AOP有两种实现方式:
- 基于接口的动态代理(Dynamic Proxy)
- 基于子类化的CGLIB代理
我们在使用Spring AOP的时候,一般是不需要选择具体的实现方式的。Spring AOP能根据上下文环境帮助我们选择一种合适的。那么是不是每次都能够这么”智能”地选择出来呢?也不尽然,下面的例子就反映了这个问题:
@Componentpublic class SampleBean implements SampleInterface { public void advicedMethod() { } public void invokeAdvicedMethod() { advicedMethod(); }}public interface SampleInterface {}
在上述代码中,我们为原来的Bean实现了一个新的接口SampleInterface,这个接口中并没有定义任何方法。这个时候,再次运行相关测试代码的时候就会出现异常(摘录了部分异常信息):
org.springframework.beans.factory.BeanCreationException: Error ceating bean with name 'com.destiny1020.SampleBeanTest': Injection of autowired dependencies failedCaused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.destiny1020.SampleBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
也就是说在Test类中对于Bean的Autowiring失败了,原因是创建SampleBeanTest Bean的时候发生了异常。那么为什么会出现创建Bean的异常呢?从异常信息来看并不明显,实际上这个问题的根源在于Spring AOP在创建代理的时候出现了问题。
这个问题的根源可以在这里得到一些线索:
Spring AOP Reference - AOP Proxies
文档中是这样描述的(每段后加上了翻译):
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied.Spring AOP默认使用标准的JDK动态代理来实现AOP代理。这能使任何借口(或者一组接口)被代理。Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces. CGLIB is used by default if a business object does not implement an interface. As it is good practice to program to interfaces rather than classes; business classes normally will implement one or more business interfaces. It is possible to force the use of CGLIB, in those (hopefully rare) cases where you need to advise a method that is not declared on an interface, or where you need to pass a proxied object to a method as a concrete type.Spring AOP也使用CGLIB代理。对于代理classes而非接口这是必要的。如果一个业务对象没有实现任何接口,那么默认会使用CGLIB。由于面向接口而非面向classes编程是一个良好的实践;业务对象通常都会实现一个或者多个业务接口。强制使用CGLIB也是可能的(希望这种情况很少),此时你需要advise的方法没有被定义在接口中,或者你需要向方法中传入一个具体的对象作为代理对象。
因此,上面异常的原因在于:
强制使用CGLIB也是可能的(希望这种情况很少),此时你需要advise的方法没有被定义在接口中。
我们需要advise的方法是SampleBean中的advicedMethod方法。而在添加接口后,这个方法并没有被定义在该接口中。所以正如文档所言,我们需要强制使用CGLIB来避免这个问题。
强制使用CGLIB很简单:
@Configuration@EnableAspectJAutoProxy(proxyTargetClass = true)@ComponentScan(basePackages = "com.destiny1020")public class CommonConfiguration {}
向@EnableAspectJAutoProxy注解中添加属性proxyTargetClass = true即可。
CGLIB实现AOP代理的原理是通过动态地创建一个目标Bean的子类来实现的,该子类的实例就是AOP代理,它建立起了目标Bean到Advice的联系。
当然还有另外一种解决方案,那就是将方法定义声明在新创建的接口中并且去掉之前添加的proxyTargetClass = true:
@Componentpublic class SampleBean implements SampleInterface { @Override public void advicedMethod() { } @Override public void invokeAdvicedMethod() { advicedMethod(); }}public interface SampleInterface { void invokeAdvicedMethod(); void advicedMethod();}@Configuration@EnableAspectJAutoProxy@ComponentScan(basePackages = "com.destiny1020")public class CommonConfiguration {}
- 从Debug Stacktrace的角度也可以看出这两种AOP实现方式上的区别:
- JDK动态代理
- CGLIB
- 关于动态代理和CGLIB这两种方式的简要总结如下:
- JDK动态代理(Dynamic Proxy)
- 基于标准JDK的动态代理功能
- 只针对实现了接口的业务对象
- CGLIB
- 通过动态地对目标对象进行子类化来实现AOP代理,上面截图中的SampleBean$$EnhancerByCGLIB$$1767dd4b即为动态创建的一个子类
- 需要指定@EnableAspectJAutoProxy(proxyTargetClass = true)来强制使用
- 当业务对象没有实现任何接口的时候默认会选择CGLIB
springaop实现原理_spring AOP的实现原理相关推荐
- spring mvc原理_Spring MVC的工作原理,我们来看看其源码实现
来源:https://www.cnblogs.com/youzhibing/p/10695012.html 作者:youzhibing2904 遗留问题 在关于利用maven搭建ssm的博客,我们一起 ...
- Spring的AOP与IOC原理
一.IOC(Inversion of Control):控制反转 传统模式下使用类的方法与属性,我们需要new出这个类的对象,然后使用对象进行方法调用,这种方法耦合度极高,为了降低耦合度,Spring ...
- Spring 容器AOP的实现原理——动态代理
本文来自极客学院 Spring 容器AOP的实现原理--动态代理 之前写了一篇关于IOC的博客--<Spring容器IOC解析及简单实现>,今天再来聊聊AOP.大家都知道Spring的两大 ...
- JAVA基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架...
1.类加载器 ·简要介绍什么是类加载器,和类加载器的作用 ·Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader ...
- 底层原理_Spring框架底层原理IoC
一.概述 Spring是一个轻量级的开源JavaEE框架 Spring可以解决企业应用开发的复杂性 Spring两大核心部分:IoC和AOP 特点: 方便解耦,简化开发 AOP编程支持 方便程序测试 ...
- spring mvc原理_Spring常见问题整理
一.为什么要使用 spring? 1.Spring简介 spring 是一个开源的轻量级 JavaBean 容器框架.使用 JavaBean 代替 EJB ,并提供了丰富的企业应用功能,降低应用开发的 ...
- aop实现原理_从宏观的实现原理和设计本质入手,带你理解 AOP 框架的原理
点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:FeelsChaotic juejin.im/post/5c57b2d5e51d45 ...
- java 事务实现原理_Spring中事务用法示例及实现原理详解
前言 Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现. 关于事务,简单来说,就是为了保证数据 ...
- 从宏观的实现原理和设计本质入手,带你理解 AOP 框架的原理
点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:FeelsChaotic juejin.im/post/5c57b2d5e51d45 ...
最新文章
- Windows 7 的系统优化方案
- 5.5 SVM补充-机器学习笔记-斯坦福吴恩达教授
- WSS 扩展文件夹的属性--如何给文件夹添加扩展字段
- 使用Vitamio打造自己的Android万能播放器(7)——在线播放(下载视频)
- 《计算机科学概论》—第3章3.3节文本表示法
- Qt中全局变量的使用
- 4012最长的最短路径的求解(C++,迪杰斯特拉算法,注释全,附迪杰斯特拉算法详解文章)
- Laravel核心解读--Facades
- 录像回放丨2020数据技术嘉年华现场视频现已上线
- Zabbix通过Smokeping检测网络质量并告警
- 从零基础入门Tensorflow2.0 ----六、32cifar10数据训练
- PowerShell 远程连接与其它技巧
- 重置mysql数据库密码_重置mysql数据库密码的方法
- English语法_分词用法-作名词
- Vue安装必要插件element-ui插件及axios依赖(详细)
- 【愚公系列】2022年10月 微信小程序-电商项目-商品详情页面的标题及价格功能实现
- 谷歌学术高级搜索技巧
- 机器人唱歌bgm_Soul app里面机器人匹配的那首bgm是什么呀?好好听!!!求玩过soul的大神告知!!...
- 【DG】[三思笔记]一步一步学DataGuard
- Excel学习日记:L31-布尔逻辑/and和or函数/sumproduct函数
热门文章
- Atomic原子类常用方法总结(包含四大类型)
- zabbix 安装_Zabbix的WEB安装与配置
- 基于RT-Thread实现的小游戏(贪吃蛇、俄罗斯方块)
- 数据结构与算法 / 哈希算法
- 服务器远程显示用户忙,服务器远程显示用户忙
- matlab cameraman,cameraman.tif 原图
- 双向TVS管 30KP42CA
- 32位微型计算机原理...,32位微型计算机原理·接口技术及其应用
- java限制数字_是否存在将我的通用方法限制为数字类型的约束?
- misc高阶 攻防世界_玄幻世界(修真、仙侠、奇幻、神话)修炼体系基础模型设定。...