Spring对AOP的实现

news2024/11/24 4:51:45

Spring对AOP实现的模式分为2种,一种是代理,一种是AspectJ,这种区分方式是直接使用实现方式区分的。

二、Spring对动态代理的设计

动态代理我们都知道在Spring中分为JDK动态代理和cglib动态代理,JDK动态代理自不用说,由Java运行时环境提供,而对于cglib,Spring将他封装在了spring-core中,足以证明动态代理在Spring中处于一个基础+核心的地位,所以我们更加有必要搞清楚Spring是如何使用cglib的,而对于Spring AOP而言,则是单独的作为一个模块出现:spring-aop。

三、2种动态代理的特点

JDK动态代理需提供接口,代理类实现的是接口中的方法,如果无法提供目标对象的接口,无法完成代理。
cglib通过继承目标类,所以无法目标类为final时无法代理,目标类中方法为final或private时无法代理。
JDK通过反射实时生成代理对象,cglib通过操作字节码生成代理对象,cglib动态代理会较JDK动态代理快。

四、AOP联盟的标准

先来看看spring-aop包的结构:



其中aopalliance是对AOP和Java有浓厚兴趣的软件开发人员联合成立的开源项目,Spring是按照AOP联盟的规范做的实现,可见Spring是一个集众多基础框架于一身的伟大软件。aopalliance包里面只有接口,没有任何实现,这就是一个规范定义。

AOP联盟定义的顶级概念有:
org.aopalliance.aop.Advice
org.aopalliance.intercept.Joinpoint
aop联盟中定义分为aop包和intercept,我们可以从这里看出aop联盟对切面的理解。advice是切面的逻辑,是切面中最直观的一个概念,其他的都是为advice服务的,要让advice工作的。
org.aopalliance.aop.Advice
aop联盟定义的advice是一个空接口,用来进行类型定义。

/**
 * Tag interface for Advice. Implementations can be any type
 * of advice, such as Interceptors.
 *
 * @author Rod Johnson
 * @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $
 */
public interface Advice {

}

org.aopalliance.intercept.Interceptor

public interface Interceptor extends Advice {

}

 org.aopalliance.intercept.Joinpoint
从实现里可以重新对连接点有一个认识,proceed()方法推进到拦截链上的下一个拦截器。getThis()方法返回持一个对象,这个对象持有当前连接点静态部分,如invocation的目标对象。getStaticPart()返回连接点的静态部分。真的很抽象。

public interface Joinpoint {

	/**
	 * Proceed to the next interceptor in the chain.
	 * <p>The implementation and the semantics of this method depends
	 * on the actual joinpoint type (see the children interfaces).
	 * @return see the children interfaces' proceed definition
	 * @throws Throwable if the joinpoint throws an exception
	 */
	Object proceed() throws Throwable;

	/**
	 * Return the object that holds the current joinpoint's static part.
	 * <p>For instance, the target object for an invocation.
	 * @return the object (can be null if the accessible object is static)
	 */
	Object getThis();

	/**
	 * Return the static part of this joinpoint.
	 * <p>The static part is an accessible object on which a chain of
	 * interceptors are installed.
	 */
	AccessibleObject getStaticPart();

}

 org.aopalliance.intercept.Invocation

public interface Invocation extends Joinpoint {

	/**
	 * Get the arguments as an array object.
	 * It is possible to change element values within this
	 * array to change the arguments.
	 * @return the argument of the invocation
	 */
	Object[] getArguments();

}

Spring对AOP的设计如下:

Spring定义的顶级概念有:
org.springframework.aop.Advisor
org.springframework.aop.Pointcut
aop联盟没有切点的概念,只有连接点,切点描述的是被切的目标,如哪些方法,连接点描述的是目标被切的位置,如方法的前后。换句话说,aop联盟定义了能切目标,不关心用户要切目标中的哪一些。aop联盟定义的概念还是更加抽象,Spring定义的概念更加贴近实现。

org.aopalliance.aop.Advice

顶级接口增强,建议,也就是要添加的代理逻辑所在位置,Advice处于设计的高层,他会使用Joinpoint
AOP联盟和Spring对Advice的设计如下,可以看出,对ConstructorInterceptor大家一点兴趣也没有,没有人对构造方法处理,BeforeAdvice和AfterAdvice的功能也可以被

org.aopalliance.intercept.Joinpoint

顶级接口连接点,是调用代理逻辑的位置,注意不是代理逻辑所在位置,可以是构造方法,普通方法,字段等,我们通常使用的是方法。所以Joinpoint中有个重要方法proceed(),意思是继续处理。
AOP联盟对Joinpoint的设计如下,看的出来,连接点的子接口就是调用,调用又分为构造方法调用和普通方法调用。

MethodInterceptor里的重要方法是:Object invoke(MethodInvocation invocation) throws Throwable;
MethodInvocation里的重要方法是继承Joinpoint的:Object proceed() throws Throwable;
我们如果要开发框架,通常会继承MethodInterceptor,它像是个钩子,会被回调,代表代理的逻辑。
MethodInvocation通常是被动态代理框架实现,比如cglib,他会去实现里面的proceed()方法。
注意MethodInterceptor会使用MethodInvocation,MethodInterceptor是设计的高层。
以上是AOP联盟对AOP规范的定义。

五、Spring在AOP联盟基础上对AOP的设计

1、代理对象生成方式的设计
Spring AOP在动态代理方式的设计如下:
org.springframework.aop.framework.AopProxy
这个接口定义的是动态代理生成的方式,开箱即用的实现有2个,分别是cglib和JDK dynamic proxies,我们也可以看到实现类为:
org.springframework.aop.framework.JdkDynamicAopProxy
org.springframework.aop.framework.CglibAopProxy
具体实现我们这里不看了

2、生成动态代理对象
org.springframework.aop.framework.ProxyFactoryBean
这里有个ProxyCreatorSupport容易被忽视,但是他是非常重要的一个类
无论是getSingletonInstance()还是newPrototypeInstance()最后都调用了一个createAopProxy(...),这个方法创建代理方式的,一般返回JdkDynamicAopProxy或CglibAopProxy,但是这个我们并不太关心,知道就行了。
getObject()方法是获取代理对象的方法,里面根据情况调用getSingletonInstance()或newPrototypeInstance()方法
这两个方法最终会调用createAopProxy(),虽然这个方法是生成一个一个AopProxy实例,但是这个AopProxy实例是对应着一个具体的客户代理实例,所以里面需要处理很多客户代理的信息
关键是createAopProxy()方法将ProxyCreatorSupport类作为参数传递进去了,也就是说,生成代理实例的时候肯定需要使用ProxyCreatorSupport类。

@SuppressWarnings("serial")
public class ProxyFactoryBean extends ProxyCreatorSupport
		implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
	...
	@Override
	@Nullable
	public Object getObject() throws BeansException {
		initializeAdvisorChain();
		if (isSingleton()) {
			return getSingletonInstance();
		}
		else {
			if (this.targetName == null) {
				logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
						"Enable prototype proxies by setting the 'targetName' property.");
			}
			return newPrototypeInstance();
		}
	}

	private synchronized Object getSingletonInstance() {
		if (this.singletonInstance == null) {
			this.targetSource = freshTargetSource();
			if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
				// Rely on AOP infrastructure to tell us what interfaces to proxy.
				Class<?> targetClass = getTargetClass();
				if (targetClass == null) {
					throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
				}
				setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
			}
			// Initialize the shared singleton instance.
			super.setFrozen(this.freezeProxy);
			this.singletonInstance = getProxy(createAopProxy());
		}
		return this.singletonInstance;
	}

	private synchronized Object newPrototypeInstance() {
		// In the case of a prototype, we need to give the proxy
		// an independent instance of the configuration.
		// In this case, no proxy will have an instance of this object's configuration,
		// but will have an independent copy.
		ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());

		// The copy needs a fresh advisor chain, and a fresh TargetSource.
		TargetSource targetSource = freshTargetSource();
		copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
		if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
			// Rely on AOP infrastructure to tell us what interfaces to proxy.
			Class<?> targetClass = targetSource.getTargetClass();
			if (targetClass != null) {
				copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
			}
		}
		copy.setFrozen(this.freezeProxy);

		return getProxy(copy.createAopProxy());
	}

	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}
	...
}

3、org.springframework.aop.framework.ProxyCreatorSupport的作用
ProxyCreatorSupport本身的逻辑很简单,100多行代理而已,都是些封装一层的逻辑而已。关键是他的父类:

public class ProxyCreatorSupport extends AdvisedSupport {
...
}

4、org.springframework.aop.framework.AdvisedSupport
这个类是一个支持类,非常关键,里面有一个advisors成员,是Advisor列表,我们知道Advice是代理逻辑所在类,而Advisor是Advice的承载类,所以可以很明确的知道,AdvisedSupport类是生成代理的基础材料,因为他包含了所有的代理逻辑
这里的命名是Advised,有几个类的作用是必须要澄清的
org.springframework.aop.framework.Advised
org.springframework.aop.Advisor
org.aopalliance.aop.Advice
Advised使用Advisor,Advisor使用Advice,其实Advisor和Advice是一个一对一的关系,Advisor是Advice的一层封装

public class AdvisedSupport extends ProxyConfig implements Advised {
	...
	private List<Advisor> advisors = new ArrayList<>();

	...
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/58482.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

没有几年经验你真学不会这份SpringCloud实战演练文档

前言 时间飞逝&#xff0c;转眼间毕业七年多&#xff0c;从事 Java 开发也六年了。我在想&#xff0c;也是时候将自己的 Java 整理成一套体系。 这一次的知识体系面试题涉及到 Java 知识部分、性能优化、微服务、并发编程、开源框架、分布式等多个方面的知识点。 写这一套 Ja…

[附源码]Python计算机毕业设计Django共享汽车系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Unity 3D 碰撞体(Collider)|| Unity 3D 触发器(Trigger)

在游戏制作过程中&#xff0c;游戏对象要根据游戏的需要进行物理属性的交互。 因此&#xff0c;Unity 3D 的物理组件为游戏开发者提供了碰撞体组件。碰撞体是物理组件的一类&#xff0c;它与刚体一起促使碰撞发生。 碰撞体是简单形状&#xff0c;如方块、球形或者胶囊形&…

零基础入门数据挖掘——二手车交易价格预测:baseline

零基础入门数据挖掘 - 二手车交易价格预测 赛题理解 比赛要求参赛选手根据给定的数据集&#xff0c;建立模型&#xff0c;二手汽车的交易价格。 赛题以预测二手车的交易价格为任务&#xff0c;数据集报名后可见并可下载&#xff0c;该数据来自某交易平台的二手车交易记录&am…

四旋翼无人机学习第12节--跨页连接符的标号设置、DRC、PDF导出

文章目录1 跨页连接符的标号设置2 DRC与原理图检查3 PDF导出1 跨页连接符的标号设置 1、在设置跨页连接符的标号之前&#xff0c;需要去修改原理图的页码。 2、按照下图所示的操作步骤依次点击。 3、接着会弹出annotate的对话框&#xff0c;按照下图进行选择&#xff0c;如果…

数据结构(9)树形结构——大顶堆、小顶堆

目录 9.1.概述 9.2.操作 9.2.1.插入 9.2.2.删除 9.2.3.代码实现 9.1.概述 概念&#xff1a; 根节点是自己所在子树中的最值的完全二叉树。 根节点是所在子树的最大值&#xff0c;称为大顶堆。 根节点是所在子树的最小值&#xff0c;称为小顶堆。 堆的任何子树的根节点…

Android OpenGL ES 学习(七) – 纹理

OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学习(三) – 绘制平面图形 Android OpenGL ES 学习(四) – 正交投屏 Android OpenGL ES 学习(五) – 渐变色 Android OpenGL ES 学习(六) – 使用…

第二证券|11天9板,“超级面料”概念火爆,高管却偷偷减持

自带抗病毒特点的“超级面料”炽热&#xff0c;多家上市公司发表相关状况。 安奈儿11天9板收重视函 早盘&#xff0c;安奈儿再度涨停&#xff0c;短短11个交易日9个涨停板&#xff0c;累计涨幅到达127%。 昨日晚间&#xff0c;安奈儿收到深交所重视函。在重视函中&#xff0c…

【计算机毕业设计】72.房屋出租出售系统源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;房屋出租出售系统当然也不能排除在外。房屋出租出售系统是…

《绿色消费实施方案》的推出,释放出怎么样的信号,有无新的赛道

近日&#xff0c;国家发改委等七部门印发的《促进绿色消费实施方案》(以下简称《方案》)提出&#xff0c;探索实施全国绿色消费积分制度&#xff0c;鼓励地方结合实际建立本地绿色消费积分制度&#xff0c;以兑换商品、折扣优惠等方式鼓励绿色消费。鼓励各类销售平台制定绿色低…

C/C++语言 数据结构 创建邻接表存储的无向图及其邻接表的输出

目录 1.邻接表相关知识补充 2. 图的邻接存储表示 3.测试输入与输出样例 4.代码实现 4.1 创建无向图邻接表 4.2 输入无向图的邻接表 1.邻接表相关知识补充 定义&#xff1a; 对于图中每个顶点 vi&#xff0c;把所有邻接于 vi的顶点&#xff08;对有向图是将从vi出发的弧的弧头顶…

windows/linux命令行操作快捷方式

命令行快捷键 Ctrla&#xff1a;光标回到命令行首。 &#xff08;a&#xff1a;ahead&#xff09; Ctrle&#xff1a;光标回到命令行尾。 &#xff08;e&#xff1a;end&#xff09; Ctrlb&#xff1a;光标向行首移动一个字符。 &#xff08;b&#xff1a;backwards&#xff…

【模拟面试】23届本科生拿下字节/京东/网易研发offer,到底有多强?

这是一场模拟面试&#xff0c;面试选手是今年的应届生&#xff0c;拿下了字节/京东/网易的offer。 如果你想参加模拟面试欢迎私聊我&#xff0c;仅限后端&#xff0c;go语言更好。 下面可以看看这个同学的简历 我个人觉得挺不错的 总共问了几个问题 你们这个计费系统是干什么的…

想要精通算法和SQL的成长之路 - 判断子序列问题

想要精通算法和SQL的成长之路 - 判断子序列问题前言一. 判断子序列1.1 动态规划做法1.2 双指针二. 不同的子序列前言 想要精通算法和SQL的成长之路 - 系列导航 一. 判断子序列 原题链接 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字…

阿里p8实战总结SpringCloud微服务分布式系统文档

前言 有人调侃我们说&#xff1a; 程序员不如送外卖。送外卖是搬运食物&#xff0c;自己是搬运代码&#xff0c;都不产出新的东西……透支体力&#xff0c;又消耗健康&#xff0c;可替代性极强&#xff0c;30岁之后就要面临被优化的危险……想跳槽&#xff0c;但是更高的平台…

Interval Envision图像库,非常强大的图像功能

Interval Envision图像库被认为具有增强Borland和Embarcadero Delphi的能力&#xff0c;并为用户和开发人员提供非常强大的图像功能。该库能够为用户提供一个图像文件I/O&#xff0c;用于文件的流行格式、扫描、打印过程、ocr的接口&#xff0c;以及最终的图片处理&#xff0c;…

Linux文件系统——文件系统、挂载点、目录结构

目录 一、目录结构 1.1 基本介绍 1.2 详细说明目录作用 二、挂载点 一、目录结构 1.1 基本介绍 Linux是一切皆文件&#xff0c;将所用的东西当做文件处理 目录结构就是一个单一的树状结构 整个的目录树只有一个树根&#xff1a;/ 根目录 文件夹分门别类的放到根目录…

vue配置环境变量

vue配置环境变量目录概述需求&#xff1a;设计思路实现思路分析1.URL管理2.网页3.加载.env4.分析参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for c…

卷积神经网络kernel/filter/stride

【关于神经网络的学习】 【参考】&#xff1a;卷积核filter和kernal的区别 - 一杯明月 - 博客园 (cnblogs.com) 【参考】&#xff1a;(1条消息) 卷积神经网络的卷积核&#xff08;kernel&#xff09;、输入尺寸&#xff08;input&#xff09;、步长&#xff08;stride&#x…

[附源码]计算机毕业设计springboot学生疫情防控信息填报系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…