当前位置: 首页 > 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;以及这一举措对互联…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...