【Spring Boot】Spring AOP动态代理,以及静态代理

news2024/9/21 4:39:38

目录

  • Spring AOP代理
    • 一. 代理的概念
    • 二. 静态代理
    • 三. JDK代理
      • 3.1 重写 invoke 方法进⾏功能增强
      • 3.2 通过Proxy类随机生成代理对象
    • 四. CGLIB代理
      • 4.1 自定义类来重写intercept方法
      • 4.2 通过Enhancer类的create方法来创建代理类
    • 五. AOP源码剖析
  • 总结(重中之重,精华)

Spring AOP代理

一. 代理的概念

根据前面的学习想必大家都已经对Spring AOP有所了解了,接下来我们先来回忆一下什么是Spring AOP?

AOP:一种对于集中的事情进行统一处理解决的思想;

Spring AOP:Spring通过运用AOP统一解决的思想所诞生的产物;
例如:拦截器,适配器,统一结果返回,统一异常处理,以及统一通知处理,以上这些在我们前面的文章中都讲述过,已经有些遗忘的小伙伴可以翻看前面的文章进行稳固一下…

好!接下来我们进入正题…

AOP的底层原理实现的代理模式,那么什么是代理模式呢?
通过举一个栗子~大家就应该能够了解了:有些 小伙伴可能通过一些线上平台租过房子,那么这个线上平台就是我们说的中介,是在我们跟房子房东之间的纽带,为啥我们要找中介呢?

  1. 中介能够帮我们提前去验收要出租房子的质量来进行出租价格的评定
  2. 中介能够在我们住房期间能够对房子的进行一个改造升级

通过上面的栗子中的 中介就是代理,我们通过中介能够达到我们最终的要求,这就是代理模式简单来说就是通过一个代理类能够间接的调用目标方法
在这里插入图片描述

然而代理模式又分为两种:

  1. 静态代理
  2. 动态代理(两种)

静态代理和动态代理的主要区别就是:静态代理的代理对象的一开始就定好的,而动态代理就跟他的命名一样,是动态化的,是由系统随机调度生成的一个代理对象
按照上面的例子来说就是,静态代理A的房子,那么A房子的中介人一直是这个人,而动态代理是中介公司看现在哪一个中介在摸鱼,就让哪一个中介去干活~
当然了,在面试中主要考查的是动态代理;

动态代理(主要是通过反射来完成的代理模式)

  1. JDK代理
  2. CGLIB代理

在接下来的讲解中我们将围绕以上几种代理进行展开,由于JDK代理和CGLIB代理是面试中的重中之重,篇幅较长,我们后面慢慢讲述,先就简单的,软的柿子——静态代理来捏~~

二. 静态代理

静态代理:由程序员创建代理类或特定⼯具⾃动⽣成源代码再对其编译,在程序运⾏前代理类的
.class⽂件就已经存在了
什么意思呢?简单来理解就是它的代理对象已经定死了,不会在修改了。

代理(中介,帮房东出租房⼦)

public class HouseProxy implements HouseSubject{

	//将被代理对象声明为成员变量
	private HouseSubject houseSubject;
	
	public HouseProxy(HouseSubject houseSubject) {
		this.houseSubject = houseSubject;
	}
	
	@Override
	public void rentHouse() {
	
		//开始代理
		System.out.println("我是中介, 开始代理");
		
		//代理房东出租房⼦
		houseSubject.rentHouse();
		
		//代理结束
		System.out.println("我是中介, 代理结束");
	}
}

这段代码不需要看明白,只用记住,代理对象通过renHouse方法来加强房子的质量,以及代理对象写死了就行了,重点全在动态代理中

三. JDK代理

在上面讲过,动态代理于静态代理的区别在于动态代理的代理对象是系统生成的,而JDK动态代理是通过:
JDK动态代理有⼀个最致命的问题是其只能代理实现了接口的类

  1. 通过实现InvocationHandler接口,重写 invoke 方法来加强被代理的对象(加强房子的质量)
  2. 通过Proxy类来随机生成一个代理对象

3.1 重写 invoke 方法进⾏功能增强

实现InvocationHandler接口,重写的 invoke 方法的伪代码如下,了解他们的区别和调用的方法即可:

public interface InvocationHandler {
/**
* 参数说明
* proxy:代理对象
* method:代理对象需要实现的方法,即其中需要重写的方法
* args:method所对应方法的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
	throws Throwable;
}

InvocationHandler接口是Java动态代理的关键接口之⼀,它定义了⼀个单⼀方法 invoke() ,⽤于
处理被代理对象的方法调⽤.通过实现 InvocationHandler 接口,可以对被代理对象的方法进⾏功能增强.

3.2 通过Proxy类随机生成代理对象

通过Proxy类来随机生成一个代理对象伪代码如下:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException
{
//...代码省略
}

Proxy 类中使⽤频率最⾼的方法是: newProxyInstance() ,这个方法主要⽤来⽣成⼀个代理
对象

这个方法⼀共有3个参数:
Loader:类加载器,⽤于加载代理对象.
interfaces:被代理类实现的⼀些接口(这个参数的定义,也决定了JDK动态代理只能代理实现了接口的
⼀些类)
h:实现了InvocationHandler接口的对象

⾃定义 InvocationHandler 并重写 invoke 方法,在 invoke 方法中我们会调⽤⽬标方
法(被代理类的方法)并⾃定义⼀些处理逻辑
3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[]
interfaces,InvocationHandler h) 方法创建代理对象

四. CGLIB代理

JDK动态代理有⼀个最致命的问题是其只能代理实现了接口的类,而CGLIB却能够实现接口也能代理类

  1. 通过⾃定义 MethodInterceptor 并重写 intercept 方法加强被代理的对象(加强房子的质量)
  2. 通过Enhancer类的create()创建代理类

和JDK动态代理不同,CGLIB(CodeGenerationLibrary)实际是属于⼀个开源项⽬,如果你要使⽤它
的话,需要⼿动添加相关依赖

<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

4.1 自定义类来重写intercept方法

⾃定义 MethodInterceptor 并重写 intercept 方法, intercept ⽤于增强⽬标方法,和JDK动态代理中的 invoke 方法类似

代码如下:

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CGLIBInterceptor implements MethodInterceptor {
	
		//⽬标对象, 即被代理对象
	private Object target;	
	
	public CGLIBInterceptor(Object target){
		this.target = target;
	}
	
	@Override
	public Object intercept(Object o, Method method, Object[] objects,MethodProxy methodProxy) throws Throwable {
	
		// 代理增强内容
		System.out.println("我是中介, 开始代理");
		
		//通过反射调⽤被代理类的方法
		Object retVal = methodProxy.invoke(target, objects);
		
		//代理增强内容
		System.out.println("我是中介, 代理结束");
		
		return retVal;
	}
}

MethodInterceptor 和JDK动态代理中的 InvocationHandler 类似,它只定义了⼀个方
法 intercept() ,⽤于增强⽬标方法

4.2 通过Enhancer类的create方法来创建代理类

通过Enhancer类的create()创建代理类

伪代码如下:

public static Object create(Class type, Callback callback) {
//...代码省略
}

参数说明:
type:被代理类的类型(类或接口)
callback:⾃定义方法拦截器MethodInterceptor

五. AOP源码剖析

SpringAOP主要基于两种方式实现的:JDK及CGLIB的方式

然而为什么会有两种不同的代理方式?以及什么时候用不同的代码方式呢?
在下面的部分源码中我们可以了解到

//创建代理⼯⼚
ProxyFactory proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);

/**
* 检查proxyTargetClass属性值,spring默认为false
* proxyTargetClass 检查接口是否对类代理, ⽽不是对接口代理
* 如果代理对象为类, 设置为true, 使⽤cglib代理
*/
if (!proxyFactory.isProxyTargetClass()) {

	//是否有设置cglib代理
	if (shouldProxyTargetClass(beanClass, beanName)) {
	
		//设置proxyTargetClass为true,使⽤cglib代理
		proxyFactory.setProxyTargetClass(true);
	} else {
	
		/**
		* 如果beanClass实现了接口,且接口⾄少有⼀个⾃定义方法,则使⽤JDK代理
		* 否则CGLIB代理(设置ProxyTargetClass为true )
		* 即使我们配置了proxyTargetClass=false, 经过这⾥的⼀些判断还是可能会将其
		设为true
		*/
		evaluateProxyInterfaces(beanClass, proxyFactory);
	}
}

从上面的部分源码来看,接下来是我自己用大白话总结出来的道理,
首先会创建一个代理工厂,用于创建两种不同的代理对象,然后源码中有一个proxyTagertClass属性来进行判断,如果proxyTagertClass为false,且实现了接口,则用代理工厂来创建一个JDK代理的对象,如果没有实现接口或者proxyTagertClass为true,则用代理工厂来创建一个CGLIB代理的对象

根据proxyTagertClass属性来创建代理对象的情况如下表格:

proxyTargetClass⽬标对象代理方式
false实现了接口jdk代理
false未实现接口(只有实现类)cglib代理
true实现了接口cglib代理
true未实现接口(只有实现类)cglib代理
注意:这里的版本不同,创建的方式也会不同,在Spring版本中proxyTagertClass属性默认的为false,然而在Spring Boot 2.0版本以后proxyTagertClass属性则默认的是true ,也就是默认使用CGLIB来代理

总结(重中之重,精华)

两大重要的动态代理:

  1. JDK动态代理
  2. CGLIB动态代理

以及它两个的区别:

  1. JDK代理主要用于实现接口,不能直接用于类;而CGLIB在实现接口和类上都可以使用
  2. JDK代理通过重写invoke方法来进行功能增强,通过proxy类来生成随机代理对象,而CGLIB代理通过自定义类来重写intercept方法,通过Enhancer类的create方法来创建代理类

从动态代理的部分源码来看,接下来是我自己用大白话总结出来的过程,
首先会创建一个代理工厂,用于创建两种不同的代理对象,然后源码中有一个proxyTagertClass属性来进行判断,如果proxyTagertClass为false,且实现了接口,则用代理工厂来创建一个JDK代理的对象,如果没有实现接口或者proxyTagertClass为true,则用代理工厂来创建一个CGLIB代理的对象

以及proxyTagertClass属性在Spring Boot 2.0版本之前默认是false,而在2.0版本以后默认为true

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

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

相关文章

【人工智能】—基于成都市各区(市)县租房价格预测建模研究

引言 随着城市化进程的加速&#xff0c;人口流动日益频繁&#xff0c;租房市场作为城市生活的重要组成部分&#xff0c;其价格波动对居民生活质量和城市经济发展具有显著影响。成都市&#xff0c;作为中国西部地区的经济、文化、交通和科技中心&#xff0c;近年来吸引了大量人…

昇思25天学习打卡营第17天|linchenfengxue

RNN实现情感分类 概述 情感分类是自然语言处理中的经典任务&#xff0c;是典型的分类问题。本节使用MindSpore实现一个基于RNN网络的情感分类模型&#xff0c;实现如下的效果&#xff1a; 输入: This film is terrible 正确标签: Negative 预测标签: Negative输入: This fil…

1.8.0-矩阵乘法的反向传播-简单推导

1相关资料 之前分享过一个博客里面写的&#xff0c;我们大致了解并记住结论的博客&#xff1a;【深度学习】7-矩阵乘法运算的反向传播求梯度_矩阵梯度公式-CSDN博客&#xff1b;这里再分享一下自然语言处理书上关于这部分的推导过程&#xff1a;3-矩阵相乘-梯度反向传播的计算…

开源模型应用落地-FastAPI-助力模型交互-进阶篇(一)

一、前言 FastAPI 的高级用法可以为开发人员带来许多好处。它能帮助实现更复杂的路由逻辑和参数处理&#xff0c;使应用程序能够处理各种不同的请求场景&#xff0c;提高应用程序的灵活性和可扩展性。 在数据验证和转换方面&#xff0c;高级用法提供了更精细和准确的控制&#…

上海慕尼黑电子展开展,启明智显携物联网前沿方案亮相

随着科技创新的浪潮不断涌来&#xff0c;上海慕尼黑电子展在万众瞩目中盛大开幕。本次展会汇聚了全球顶尖的电子产品与技术解决方案&#xff0c;成为业界瞩目的焦点。启明智显作为物联网彩屏显示领域的佼佼者携产品亮相展会&#xff0c;为参展者带来了RTOS、LINUX全系列方案及A…

【见刊通知】MVIPIT 2023机器视觉、图像处理与影像技术国际会议

MVIPIT 2023&#xff1a;https://ieeexplore.ieee.org/xpl/conhome/10578343/proceeding 入库Ei数据库需等20-50天左右 第二届会议征稿启动&#xff08;MVIPIT 2024&#xff09; The 2nd International Conference on Machine Vision, Image Processing & Imaging Techn…

java —— tomcat 部署项目

一、通过 war 包部署 1、将项目导出为 war 包&#xff1b; 2、将 war 包放置在 tomcat 目录下的 webapps 文件夹下&#xff0c;该 war 包稍时便自动解析为项目文件夹&#xff1b; 3、启动 tomcat 的 /bin 目录下的 startup.bat 文件&#xff0c;此时即可从浏览器访问项目首页…

3.Python学习:模块\包\yaml

1.模块与包–互相引用 &#xff08;1&#xff09;一个模块就是一个.py文件 &#xff08;2&#xff09;有模块的目录–文件夹 &#xff08;3&#xff09;包&#xff1a;文件夹包含__init__.py文件 &#xff08;4&#xff09;导入包时&#xff0c;init.py文件里的内容会执行一次 …

聚鼎装饰画:装饰画喊个与现在是什么情况

回眸历史长河&#xff0c;装饰画以其独特的魅力一直为人类生活环境添彩增趣。从古埃及的壁画到文艺复兴时期的油画&#xff0c;再到现代简约的线条画&#xff0c;装饰画如同时代的缩影&#xff0c;映射出不同历史阶段的文化特征与审美趣味。 在现代社会&#xff0c;装饰画的现状…

C语言学习笔记[21]:分支语句if...else

C语言是结构化的程序设计语言 顺序结构选择结构循环结构 分支语句对应的就是选择结构&#xff0c;循环语句对应的就是循环结构 分支语句 if...elseswitch 循环语句 whilefordo...while goto语句 语句 C语言中由分号隔开的就是一条语句&#xff0c;比如&#xff1a; #…

猫咪浮毛多怎么办?一分钟推荐性价比高的养猫空气净化器排名

作为一名猫咖店老板&#xff0c;我发现很多铲屎官来店里咨询&#xff0c;在春夏换季时会频繁打喷嚏、全身过敏红肿。这是因为猫咪在换季时会大量掉毛&#xff0c;家里就像下雪一样&#xff0c;空气中充满了猫毛。这些猫毛上附带的细菌会随浮毛被人吸入&#xff0c;从而引发打喷…

【计算机毕业设计】021基于weixin小程序微信点餐

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

奇安信20240513笔试

题目一 解题思路 n转为字符串&#xff0c;如果位数为偶数&#xff0c;取前一半设为x&#xff0c;后一段为y&#xff0c;从x最低位开始&#xff0c;9&#xff0c;9*10&#xff0c;9*10*10。。。 到最高位&#xff0c;加x&#xff0c;如果x大于或等于y&#xff0c;加1. 位数为奇数…

数据结构——二叉树之c语言实现堆与堆排序

目录 前言&#xff1a; 1.二叉树的概念及结构 1.1 特殊的二叉树 1.2 二叉树的存储结构 1.顺序存储 2.链式存储 2. 二叉树的顺序结构及实现 2.1 堆的概念 ​编辑 2.2 堆的创建 3.堆的实现 3.1 堆的初始化和销毁 初始化&#xff1a; 销毁&#xff1a; 插入&…

React Hooks:上天在提醒你,别再用Class组件了!

React Hooks&#xff1a;上天在提醒你&#xff0c;别再用Class组件了&#xff01; React Hooks 的出现可以说是前端界的一场革命。它不仅让我们告别了繁琐的 Class 组件&#xff0c;还让代码变得更加简洁、易读、易维护。如果你还在固守 Class 组件的阵地&#xff0c;那么这篇…

如何处理 PostgreSQL 中由于表锁定导致的并发访问问题?

文章目录 一、表锁定的类型二、表锁定导致的并发访问问题三、解决方案&#xff08;一&#xff09;使用合适的锁定模式&#xff08;二&#xff09;优化事务处理&#xff08;三&#xff09;避免不必要的锁定&#xff08;四&#xff09;使用索引&#xff08;五&#xff09;监控和分…

Java-链表反转

题目&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 图示&#xff1a; 输入&#xff1a; head [1,2,3,4,5] 输出&#xff1a; [5,4,3,2,1] 解题思路&#xff1a; 情况一&#xff1a; 只有一个节点或者没有节点 …

小白学C++(第一天)基础入门

温馨提醒&#xff1a;本篇文章&#xff0c;请各位c基础不行的童鞋不要贸然观看 C的第一个程序 第一个关键字namespace namespace 是定义空间的名字的关键字&#xff0c;使用格式格式如下&#xff1a; namespace 空间名 { } 其中{ }内的命名空间的成员&#xff0c;可以定义…

计算机图形学入门26:高级光线传播

1.有偏与无偏 在做光线追踪很多方法都是用蒙特卡洛积分去估计&#xff0c;蒙特卡洛积分有些是无偏的(Unbiased)&#xff0c;所谓无偏估计就是无论使用多少个样品&#xff0c;所估计的期望值都是正确的。那么&#xff0c;所有其他情况都是有偏的(Biased)&#xff0c;就是估计的期…

MySQL存储与优化 一、MySQL架构原理

1.MySQL体系架构 MySQL Server架构自顶向下大致可以分网络连接层、服务层、存储引擎层和系统文件层 (1)网络连接层 客户端连接器&#xff08;Client Connectors&#xff09;&#xff1a;提供与MySQL服务器建立的支持。目前几乎支持所有主流的服务端编程技术&#xff0c;例如常…