设计模式 代理模式(静态代理 动态代理) 与 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
工厂的 getProxyClass
与 getProxy
两个方法创建的
我们来看一下这两个方法具体实现
通过 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文件用来游戏的逻辑测试,在分别开一个game.c文件和game.h头文件用来实现游戏的逻辑 主要步骤: 游戏规则: 输入1(0)开始(结束)游戏,输入一个坐标,如果该坐…...
Java读取制表符文本转换为JSON
在Java开发中,处理各种数据格式是常见的任务。本文将介绍如何使用Java读取制表符文本文件,并将其转换为JSON格式,以便于后续的数据处理和分析。我们将使用Java中的相关库来实现这个过程,并提供详细的代码示例。 引言:…...
从C到C++:向面向对象过渡的技巧与诀窍
从C到C的过渡是一项对于程序员来说非常重要的转变。C是一种基于C语言的面向对象编程语言,它引入了许多新的概念和功能,如类、对象、继承和多态等。这些新的特性使得C在软件开发中更加灵活、可复用和易于维护。 下面是一些向面向对象过渡的技巧和诀窍&am…...

Vue3中动态组件使用
一,动态组件使用: 应用场景:动态绑定或切换组件 应用Vue3碎片: 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 的副本当有节点加入集群时, 也会为他们新增一个 Pod。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。 简而言之…...

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

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

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

workflow源码解析:ThreadTask
1、使用程序,一个简单的加法运算程序 #include <iostream> #include <workflow/WFTaskFactory.h> #include <errno.h>// 直接定义thread_task三要素 // 一个典型的后端程序由三个部分组成,并且完全独立开发。即:程序协议算…...
为何谷歌强制要求安装ssl证书?
在当今数字化的世界中,网络安全已成为至关重要的议题之一。作为全球最大的搜索引擎之一,谷歌一直在推动网络安全标准的提升。其强制要求网站安装SSL证书的决策引起了广泛关注。本文将深入探讨谷歌为何强制要求安装SSL证书,以及这一举措对互联…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...