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

设计模式 代理模式(静态代理 动态代理) 与 Spring Aop源码分析 具体是如何创建Aop代理的

代理模式

代理模式是一种结构型设计模式,它通过创建一个代理对象来控制对真实对象的访问。这种模式可以用于提供额外的功能操作,或者扩展目标对象的功能。

在代理模式中,代理对象与真实对象实现相同的接口,以便在任何地方都可以使用相同的接口来调用真实对象的方法。这样做的好处是可以在不改变原始代码的情况下,增加或修改代码的行为。

根据创建代理对象的方式和时机,代理模式可以被分为静态代理、动态代理等类型。其中,静态代理是由程序员在编译时期就定义好的代理类,而动态代理则是在程序运行时期通过Java反射机制动态生成的。

在实际生活中,有许多应用了代理模式的场景,例如租房、卖房、家政等业务,通常由中介机构作为代理来进行操作。

静态代理

静态代理在编译期间就已经确定代理类的代码。具体来说,要实现静态代理需要手动编写代理类的代码,因此这种方式的灵活性相对较差,但由于代理类是直接编写的,所以其运行效率较高。

首先定义购房者的行为

/*** 购房者** @author LionLi*/
public interface Homebuyer {/*** 需求*/String need();/*** 购买*/void buy();
}

定义真实购房者

/*** 购房者 张三** @author LionLi*/
public class Zhangsan implements Homebuyer {/*** 需求*/@Overridepublic String need() {String need = "100平以上三室两厅两卫";System.out.println("张三: " + need);return need;}/*** 购买*/@Overridepublic void buy() {System.out.println("张三: 我已付款");}
}
/*** 购房者 王五** @author LionLi*/
public class Wangwu implements Homebuyer {/*** 需求*/@Overridepublic String need() {String need = "70平左右两室一厅";System.out.println("王五: " + need);return need;}/*** 购买*/@Overridepublic void buy() {System.out.println("张三: 我已付款");}
}

定义房产中介

/*** 房产中介代理人** @author LionLi*/
public class HouseAgentProxy implements Homebuyer {private Homebuyer homebuyer;public HouseAgentProxy(Homebuyer homebuyer) {this.homebuyer = homebuyer;}@Overridepublic String need() {System.out.println("中介: 你对房子有什么需求 放心交给我");String need = homebuyer.need();System.out.println("中介: 寻找房源中........");System.out.println("中介: 寻找房源中........");System.out.println("中介: 寻找房源中........");String str = "中介: 为您找到" + need + "的房子";System.out.println(str);return str;}@Overridepublic void buy() {System.out.println("中介: 请支付购买房子");homebuyer.buy();System.out.println("中介: 合同生效中.....");System.out.println("中介: 房证办理中.....");System.out.println("中介: 恭喜您 这套房子属于您了");}
}

测试

/*** @author LionLi*/
public class Test {public static void main(String[] args) {Homebuyer zhangsan = new Zhangsan();HouseAgentProxy agent1 = new HouseAgentProxy(zhangsan);agent1.need();agent1.buy();System.out.println("-----------------------------");Homebuyer wangwu = new Wangwu();HouseAgentProxy agent2 = new HouseAgentProxy(wangwu);agent2.need();agent2.buy();}
}

两位购房者分别根据需求在中介的带领下买到了房子 真是可喜可贺啊

动态代理

动态代理允许在运行时动态地创建代理对象。代理对象可以在调用实际对象的方法前后执行一些额外的操作,比如日志记录、权限检查等。

动态代理的实现方式有两种:基于接口和基于继承。基于接口的方式是最常用的,它使用Java的反射机制来实现代理对象。基于继承的方式则需要创建一个实现了目标类接口的子类,并重写其中的方法。

优点: 可以降低系统的耦合度,提高代码的可维护性和可扩展性。
缺点: 需要使用反射机制,性能比静态代理略低。

首先定义购房者的行为与实际购房者

使用上方代码不变

定义房产中介

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 动态房产中介代理人** @author LionLi*/
public class DynamicHouseAgentProxy implements InvocationHandler {private Homebuyer homebuyer;public Homebuyer getInstance(Homebuyer homebuyer) {this.homebuyer = homebuyer;return (Homebuyer) Proxy.newProxyInstance(homebuyer.getClass().getClassLoader(), homebuyer.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().equals("need")) {System.out.println("中介: 你对房子有什么需求 放心交给我");String need = (String) method.invoke(homebuyer, args);System.out.println("中介: 寻找房源中........");System.out.println("中介: 寻找房源中........");System.out.println("中介: 寻找房源中........");String str = "中介: 为您找到" + need + "的房子";System.out.println(str);return str;} else if (method.getName().equals("buy")) {System.out.println("中介: 请支付购买房子");Object invoke = method.invoke(homebuyer, args);System.out.println("中介: 合同生效中.....");System.out.println("中介: 房证办理中.....");System.out.println("中介: 恭喜您 这套房子属于您了");return invoke;}return null;}
}

测试

/*** @author LionLi*/
public class Test {public static void main(String[] args) {DynamicHouseAgentProxy agent = new DynamicHouseAgentProxy();Homebuyer zhangsan = new Zhangsan();Homebuyer proxy1 = agent.getInstance(zhangsan);proxy1.need();proxy1.buy();System.out.println("-----------------------------");Homebuyer wangwu = new Wangwu();Homebuyer proxy2 = agent.getInstance(wangwu);proxy2.need();proxy2.buy();}}


结果不变 两位购房者成功买到房子

Cglib动态代理

其他代码不变只变更中介类

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** 动态房产中介代理人** 这里由于cglib已经不支持jdk17了 所以我们使用spring内部自带的cglib工具** @author LionLi*/
public class DynamicHouseAgentProxy implements MethodInterceptor {public Homebuyer getInstance(Homebuyer homebuyer) {Enhancer enhancer = new Enhancer();// 设置继承父类enhancer.setSuperclass(homebuyer.getClass());// 设置回调enhancer.setCallback(this);return (Homebuyer) enhancer.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {if (method.getName().equals("need")) {System.out.println("中介: 你对房子有什么需求 放心交给我");String need = (String) proxy.invokeSuper(obj, args);System.out.println("中介: 寻找房源中........");System.out.println("中介: 寻找房源中........");System.out.println("中介: 寻找房源中........");String str = "中介: 为您找到" + need + "的房子";System.out.println(str);return str;} else if (method.getName().equals("buy")) {System.out.println("中介: 请支付购买房子");Object invoke = proxy.invokeSuper(obj, args);System.out.println("中介: 合同生效中.....");System.out.println("中介: 房证办理中.....");System.out.println("中介: 恭喜您 这套房子属于您了");return invoke;}return null;}
}

Spring中代理模式的应用

要说起Spring中的代理模式 要首当其冲的肯定是AOP了 接下来我们来看看在AOP中是如何使用代理模式的

这里涉及到一个注解 学过AOP的都知道 如果需要开启AOP那么需要增加这个注解

通过搜索找到 AspectJAutoProxyRegistrar 类, 该方法的作用就是往Spring容器中添加一个 BeanDefinition 类型为 AnnotationAwareAspectJAutoProxyCreator 用于创建代理对象


接下来我们进入 AnnotationAwareAspectJAutoProxyCreator 看看是如何创建代理的

由于 AnnotationAwareAspectJAutoProxyCreator 中并没有创建代理的方法 那么我们只能向上去父类里找, 通过不断的探索在 AnnotationAwareAspectJAutoProxyCreator -> AspectJAwareAdvisorAutoProxyCreator -> AbstractAdvisorAutoProxyCreator -> AbstractAutoProxyCreator 抽象类 AbstractAutoProxyCreator 中找到了 createProxy 方法


此方法是bean初始化的前置处理器 postProcessBeforeInstantiation 中使用的, 也就是说bean在初始化之前, 代理对象就已经创建好了

进入 createProxy 方法

进入 buildProxy 方法


这里我们可以看出 实际的代理对象是通过 ProxyFactory 工厂的 getProxyClassgetProxy 两个方法创建的

我们来看一下这两个方法具体实现

通过 getProxyClass 方法一直往下点 找到最终创建方法 DefaultAopProxyFactory#createAopProxy 为止


最后我们来分析最终是如何创建代理对象的

相关文章:

设计模式 代理模式(静态代理 动态代理) 与 Spring Aop源码分析 具体是如何创建Aop代理的

代理模式 代理模式是一种结构型设计模式,它通过创建一个代理对象来控制对真实对象的访问。这种模式可以用于提供额外的功能操作,或者扩展目标对象的功能。 在代理模式中,代理对象与真实对象实现相同的接口,以便在任何地方都可以使…...

【EI会议征稿通知】第七届先进电子材料、计算机与软件工程国际学术会议(AEMCSE 2024)

第七届先进电子材料、计算机与软件工程国际学术会议(AEMCSE 2024) 2024 7th International Conference on Advanced Electronic Materials, Computers and Software Engineering 第七届先进电子材料、计算机与软件工程国际学术会议(AEMCSE 2024)将于2024年5月10-1…...

Verilog基础:强度建模(一)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 一、强度建模基础 Verilog HDL提供了针对线网信号0、1、x、z的精准强度建模方式,这样可以允许将两个线网信号进行线与操作从而更加精确地描述出硬件行…...

Spring Boot各类变量的使用

文章目录 1. 变量类型2. 获取变量2.1 获取方式2.2 获取方法2.2.1 通过Value注入获取变量值2.2.2 System.genenv 获取变量值2.2.3 System.getProperty 获取变量值2.2.4 Environment 获取变量值2.2.5 ConfigurationProperties 获取变量值2.2.6 SpringApplication.run 程序启动参数…...

Hive管理UDF详解

大数据集群下,共有三种管理Hive UDF的方式,如下: 名称重启Hive服务Jar保存目录场景直接JAR配置需要HDFS开发辅助JARs目录配置需要本地目录防止意外覆盖文件可重载辅助JAR配置不需要本地目录频繁更新UDF场景{HIVE_HOME}/auxlib目录需要本地目录不建议{HIVE_HOME}/lib目录需要…...

bug笔记:解决 HTTP Error 500.30 - ASP.NET Core app failed to start

总结下后端部署windos iis环境net6版本,500.30问题报错的一种解决方案: 一、问题描述 二、解决方案 检查下是否安装了net6对应的环境,是否已经安装 然后在事件管理器>Windows日志>应用程序,里面查看详细异常记录 在iis下面…...

理解pytorch系列:transpose是怎么实现的

在PyTorch中,transpose()是一种操作,它交换张量中两个指定维度的位置。实现这一点的关键在于不实际移动数据,而是通过改变张量的元数据(包括步长(stride)和尺寸(size))来…...

Linux tftp命令教程:文件传输利器(附案例详解和注意事项)

Linux tftp命令介绍 tftp,全称为Trivial File Transfer Protocol(简单文件传输协议)。tftp是一个用于文件传输的客户端命令,用于从远程主机传输文件,包括一些非常简洁、通常嵌入的系统。 Linux tftp命令适用的Linux版…...

beego的模块篇 - task任务

利用该工具来定时的做一些任务,但是有些时候我们的进程内也希望定时的来处理一些事情,可以使用crontab。 1 任务计划 1.1 初始化一个任务 tk1 : task.NewTask("tk1", "0 12 * * * *", func(ctx context.Context) error { fmt.Pri…...

ThreadLocal工具类

ThreadLocal工具类 ThreadLocalUtil.java public class ThreadLocalUtil {static final ThreadLocal THREAD_LOCAL new ThreadLocal();public static <T> T get() {return (T) THREAD_LOCAL.get();}public static void set(Object value) {THREAD_LOCAL.set(value);}p…...

【c语言】扫雷(上)

先开一个test.c文件用来游戏的逻辑测试&#xff0c;在分别开一个game.c文件和game.h头文件用来实现游戏的逻辑 主要步骤&#xff1a; 游戏规则&#xff1a; 输入1&#xff08;0&#xff09;开始&#xff08;结束&#xff09;游戏&#xff0c;输入一个坐标&#xff0c;如果该坐…...

Java读取制表符文本转换为JSON

在Java开发中&#xff0c;处理各种数据格式是常见的任务。本文将介绍如何使用Java读取制表符文本文件&#xff0c;并将其转换为JSON格式&#xff0c;以便于后续的数据处理和分析。我们将使用Java中的相关库来实现这个过程&#xff0c;并提供详细的代码示例。 引言&#xff1a;…...

从C到C++:向面向对象过渡的技巧与诀窍

从C到C的过渡是一项对于程序员来说非常重要的转变。C是一种基于C语言的面向对象编程语言&#xff0c;它引入了许多新的概念和功能&#xff0c;如类、对象、继承和多态等。这些新的特性使得C在软件开发中更加灵活、可复用和易于维护。 下面是一些向面向对象过渡的技巧和诀窍&am…...

Vue3中动态组件使用

一&#xff0c;动态组件使用&#xff1a; 应用场景&#xff1a;动态绑定或切换组件 应用Vue3碎片&#xff1a; is 1.使用 a.组件A <div class"layout-base"><Button>红茶</Button> </div>a.组件B <div class"layout-base"&g…...

kubernetes工作负载-DamonSet

一、DemonSet的介绍 1、什么是DemonSet DaemonSet 控制器是用来保证在所有节点上运行一个 Pod 的副本当有节点加入集群时&#xff0c; 也会为他们新增一个 Pod。 当有节点从集群移除时&#xff0c;这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。 简而言之…...

zabbix其他配置

自动发现 zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多&#xff0c;zabbix server 登记耗时较久&#xff0c;且压力会较大。 systemctl disable --now firewalld setenforce 0 hostnamectl se…...

蓝桥杯备战 每日一题 (2)

今天的题目是回忆迷宫 这个题目我们来熟悉一下 弗洛伊德算法 的代码模板 弗洛伊德算法用来处理最短路径问题 弗洛伊德算法&#xff08;Floyd’s algorithm&#xff09;用于解决图中所有节点对之间的最短路径问题。算法的基本思路是通过逐步迭代更新节点对之间的最短路径长度&a…...

GetShell的姿势

0x00 什么是WebShell 渗透测试工作的一个阶段性目标就是获取目标服务器的操作控制权限&#xff0c;于是WebShell便应运而生。Webshell中的WEB就是web服务&#xff0c;shell就是管理攻击者与操作系统之间的交互。Webshell被称为攻击者通过Web服务器端口对Web服务器有一定的操作权…...

workflow源码解析:ThreadTask

1、使用程序&#xff0c;一个简单的加法运算程序 #include <iostream> #include <workflow/WFTaskFactory.h> #include <errno.h>// 直接定义thread_task三要素 // 一个典型的后端程序由三个部分组成&#xff0c;并且完全独立开发。即&#xff1a;程序协议算…...

为何谷歌强制要求安装ssl证书?

在当今数字化的世界中&#xff0c;网络安全已成为至关重要的议题之一。作为全球最大的搜索引擎之一&#xff0c;谷歌一直在推动网络安全标准的提升。其强制要求网站安装SSL证书的决策引起了广泛关注。本文将深入探讨谷歌为何强制要求安装SSL证书&#xff0c;以及这一举措对互联…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...

Canal环境搭建并实现和ES数据同步

作者&#xff1a;田超凡 日期&#xff1a;2025年6月7日 Canal安装&#xff0c;启动端口11111、8082&#xff1a; 安装canal-deployer服务端&#xff1a; https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...

leetcode_69.x的平方根

题目如下 &#xff1a; 看到题 &#xff0c;我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历&#xff0c;我们是整数的平方根&#xff0c;所以我们分两…...