静态代理和动态代理的区别以及实现过程
前言
代理模式是一种设计模式,能够使得在不修改源目标的前提下,额外扩展源目标的功能。即通过访问源目标的代理类,再由代理类去访问源目标。这样一来,要扩展功能,就无需修改源目标的代码了。只需要在代理类上增加就可以了。

其实代理模式的核心思想就是这么简单,在java中,代理又分静态代理和动态代理2种,其中动态代理根据不同实现又区分基于接口的的动态代理和基于子类的动态代理。
其中静态代理由于比较简单,面试中也没啥问的,在代理模式一块,问的最多就是动态代理,而且动态代理也是spring aop的核心思想,spring其他很多功能也是通过动态代理来实现的,比如拦截器,事务控制等。
熟练掌握动态代理技术,能让你业务代码更加精简而优雅。如果你需要写一些中间件的话,那动态代理技术更是必不可少的技能包。
静态代理
静态代理,就是通过声明一个明确的代理类来访问源对象。
我们有1个接口,Person。这个个接口各有2个实现类,UML如下图:

实现
接口:person.java
package StaticProxy;/*** @author zyz* @version 1.0* @data 2023/2/15 13:29* @Description:*/
public interface Person {/*** 起床*/public void wakeup();/*** 睡觉*/public void sleep();
}
实现类:Student .java
package StaticProxy;/*** @author zyz* @version 1.0* @data 2023/2/15 13:32* @Description:*/
public class Student implements Person{private String name;public Student(){}public Student(String name){this.name = name;}@Overridepublic void wakeup() {System.out.println("学生:"+name+",起床了!!!");}@Overridepublic void sleep() {System.out.println("学生:"+name+",睡觉了!!!");}
}
假设我们现在要做一件事,就是在所有的实现类调用wakeup()前增加一行输出早安,调用sleep()前增加一行输出晚安。那我们只需要编写1个代理类PersonProxy
代理类:PersonProxy .java
package StaticProxy;/*** @author zyz* @version 1.0* @data 2023/2/15 13:35* @Description:*/
public class PersonProxy implements Person{private Person person;public PersonProxy(Person person){this.person = person;}@Overridepublic void wakeup() {System.out.println("早上好啊!!!");person.wakeup();}@Overridepublic void sleep() {System.out.println("晚上好啊!!!");person.sleep();}
}
测试类
package StaticProxy;/*** @author zyz* @version 1.0* @data 2023/2/15 13:37* @Description:*/
public class Test {public static void main(String[] args) {Person student1 = new Student("张三");PersonProxy studentProxy = new PersonProxy(student1);studentProxy.wakeup();studentProxy.sleep();}
}
结果

结论:
静态代理的代码相信已经不用多说了,代码非常简单易懂。这里用了1个代理类,代理了Person接口。
这种模式虽然好理解,但是缺点也很明显:
- 会存在大量的冗余的代理类,这里演示了1个接口,如果有10个接口,就必须定义10个代理类。
- 不易维护,一旦接口更改,代理类和目标类都需要更改。
动态代理
动态代理,通俗点说就是:无需声明式的创建java代理类,而是在运行过程中生成"虚拟"的代理类,被ClassLoader加载。从而避免了静态代理那样需要声明大量的代理类。
JDK从1.3版本就开始支持动态代理类的创建。主要核心类只有2个:java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。
还是前面那个例子,用JDK动态代理类去实现的代码如下:
创建一个JdkProxy类,用于统一代理:
package DynamicProxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** @author zyz* @version 1.0* @data 2023/2/15 13:28* @Description:*/
public class JdkProxy implements InvocationHandler {private Object bean;public JdkProxy(Object bean) {this.bean = bean;}/*** 其中proxy为代理过之后的对象(并不是原对象),method为被代理的方法,args为方法的参数。** 如果你不传原有的bean,直接用method.invoke(proxy, args)的话,那么就会陷入一个死循环。* @param proxy* @param method* @param args* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();if (methodName.equals("wakeup")) {System.out.println("早安~~~");} else if (methodName.equals("sleep")) {System.out.println("晚安~~~");}return method.invoke(bean, args);}
}
测试
package DynamicProxy;import StaticProxy.Person;
import StaticProxy.Student;import java.lang.reflect.Proxy;/*** @author zyz* @version 1.0* @data 2023/2/15 13:46* @Description:*/
public class Test {public static void main(String[] args) {JdkProxy proxy = new JdkProxy(new Student("李四"));Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);student.wakeup();student.sleep();}
}
结果

可以看到,相对于静态代理类来说,无论有多少接口,这里只需要一个代理类。核心代码也很简单。唯一需要注意的点有以下2点:
JDK动态代理是需要声明接口的,创建一个动态代理类必须得给这个”虚拟“的类一个接口。可以看到,这时候经动态代理类创造之后的每个bean已经不是原来那个对象了。
这里JdkProxy最核心的方法就是
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
其中proxy为代理过之后的对象(并不是原对象),method为被代理的方法,args为方法的参数。
如果你不传原有的bean,直接用method.invoke(proxy, args)的话,那么就会陷入一个死循环。
相关文章:
静态代理和动态代理的区别以及实现过程
前言 代理模式是一种设计模式,能够使得在不修改源目标的前提下,额外扩展源目标的功能。即通过访问源目标的代理类,再由代理类去访问源目标。这样一来,要扩展功能,就无需修改源目标的代码了。只需要在代理类上增加就可…...
Consul SpringCloudK8S
背景说起微服务,就需要用到SpringCloud,目前市面上主流的SpringCloud产品有这些:SpringCloudNeflix、Spring Cloud Alibaba、Spring Cloud for AWS、Spring Cloud Azure 和 Spring Cloud Kubernetes。其中SpringCloudNeflix已经不在更新&…...
anaconda3文件夹被移动之后,如何操作可以复用原有conda环境
anaconda3文件夹被移动A-调整conda PATH地址B-更改.conda/environments.txt中的地址C-修改conda内的变量和每个环境的pip目录A-调整conda PATH地址 B-更改.conda/environments.txt中的地址 a. 优先切换到用户根目录 b. 查看隐藏conda目录 c. 编辑 vi .conda/environments.txt…...
【Java】Stack(栈) Queue(单向队列) Deque(双向队列)
Stack (栈) Stack 是一个先进后出的栈,可以将其理解为一个只开了一个口子的管子,放进去的东西只能从这一个口进出。所以先放进去的元素在取出的时候只能到最后才能取出来。 Stack具备一下几个方法: boolean empty() …...
自定义spring拦截器
说明: 一些版本比较老的spring框架的,是通过继承HandlerInterceptorAdapter并重写preHandle()方法,和继承WebMvcConfigurerAdapter并重写 addInterceptors()方法来实现拦截器的,但是这两个类很久前就已经过时了,不推荐…...
今天正式上线!虹科汽车免拆诊断云展厅:感受精准修车魅力,畅享汽修领先技术
『虹科汽车免拆诊断云展厅』 2月15日正式上线! 在这里,您可以参观了解: 虹科Pico汽车示波器产品模型 全流程专业讲解的视频资料 产品功能和应用场景 全面详细的产品手册 还有虹科首席技术工程师在线连麦答疑!!…...
4.数据类型-字符串【Python】
文章目录字符串索引切片转义字符格式化符号f-string字符串操作判断&检测转换剪切&填充拼接统计格式转化练习字符串 字符串是 Python 中最常用的数据类型。可以使用单引号,双引号,3对双引号创建一个字符串。Python 中没有单独的字符类型 char…...
搞量化先搞数(上):A股股票列表免费抓取实战
到了这一步,我们学习了基础的爬虫请求库urllib和requests,尤其是后者,强大且易用,极其适合新手使用。那么今天我们就找一个相对简单的案例,来看一下如何在实战中应用爬虫技能。 相信很多朋友都对股票感兴趣,甚至有些朋友想要通过量化研究来获得超额收益。然而,想要进行…...
SpringCloud-负载均衡Ribbon
一、配置使用1、添加依赖(该依赖包含在eureka-client依赖中)<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency>2、在RestTemp…...
Linux入门篇(二)
Linux前言链接文件符号链接(软链接)硬链接shellshell 的类型shell的父子关系理解外部命令和内建命令外部命令内建命令Linux环境变量PATH环境变量前言 在这一章,我对Linux中有关shell较为深入的理解和环境变量方面知识的一个记录。同时&#x…...
第四部分:特殊用途的句子——第三章:虚拟
虚拟语气 1、什么是虚拟? 虚拟就是非真实。换句话说,这事不是真的,这事不太可能成真,非真实,就是虚拟 2、怎么表示虚拟? 英语是一个典型的形式来补充内容的语言,若要表达虚拟,只…...
Java中如何获取泛型类型信息
文章目录声明侧泛型使用侧泛型获取泛型类型相关方法1. Class类的泛型方法2. Field类的泛型方法3. Method类的泛型方法4. ParameterizedType类获取声明侧的泛型类型信息获取使用侧的泛型类型信息匿名内部类实现获取使用侧的泛型类型根据使用泛型位置的不同可以分为:声…...
【云原生】centos7搭建安装k8s集群 v1.25版本详细教程实战
文章目录前言一. 实验环境二. k8s 的介绍三 . k8s的安装3.1 搭建实验环境3.1.1 硬件层面的要求3.1.2 软件层面环境配置3.2 docker的安装3.2.1 搭建docker3.2.2 部署 cri-dockerd3.3 部署k8s3.3.1 配置添加阿里云的yum源3.3.2 安装kubeadm kubelet kubectl3.3.3 k8s-master节点初…...
c语言指针
指针 指针是存放地址的变量,也可以说指针地址。 对于定义p(这里的话,只是定义,说明p是指针),p作为一个指针去指向存放数据的位置,而p意思是取(p指向的内存位置的数据)&…...
5.33 综合案例2.0 -ESP32拍照上传阿里云OSS
综合案例2.0 - ESP32拍照上传阿里云OSS案例说明连线功能实现1.阿里云平台连接2.OSS对象存储服务3.ESP32-CAM开发环境4.代码ESP32-CAM开发板代码HaaS506开发板代码测试数据转图片方法案例说明 使用ESP32拍照,将照片数据上传阿里云OSS(通过4G网络上传)。 …...
java无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: s “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “…...
测试用例设计工作中的应用
1. 等价类划分 常见的软件测试面试题划分等价类: 等价类是指某个输入域的子集合.在该子集合中,各个输入数据对于揭露程序中的错误都是等效的.并合理地假定:测试某等价类的代表值就等于对这一类其它值的测试.因此,可以把全部输入数据合理划分为假设干等价类,在每一个等价类中取一…...
leetcode 困难 —— 数字 1 的个数(简单逻辑题)
(害,做题是真的慢,这面试给我这题我估计就傻了) 题目: 给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。 题解: 首先看看整数范围 0 < n < 10^9 不能遍历࿰…...
关于JSON
<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> </head> <body> <script> /* 1、JSON的英文全称:Java…...
Apifox-接口调用、自动化测试工具
Apifox简介 Apifox 的定位是Postman Swagger Mock JMeter,具有API文档管理、API调试、API Mock、API 自动化测试等功能。可以通过一种工具解决之前使用多种工具的数据同步问题。高效、及时、准确! 安装 Apifox的安装非常方便,直接下载安…...
别再死记硬背了!用Pointer Network搞定NLP里的OOV难题(附代码实战)
Pointer Network实战:如何优雅解决NLP中的OOV难题 在电商客服机器人开发中,你是否遇到过这样的尴尬场景:当用户询问"冰墩墩什么时候补货"时,机器人却回复"该商品暂无库存"——它完全没理解"冰墩墩"…...
【仅限奇点大会注册开发者获取】:Istio for AI策略模板库(含RAG路由、推理超时分级、Token流控等12个YAML黄金配置)
更多请点击: https://intelliparadigm.com 第一章:AI原生服务网格应用:2026奇点智能技术大会Istio for AI 在2026奇点智能技术大会上,Istio社区正式发布 Istio for AI —— 一个专为大模型推理、微调与多租户AI工作负载设计的服务…...
一键解锁B站缓存视频:从平台依赖到个人数字资产管理的智能方案
一键解锁B站缓存视频:从平台依赖到个人数字资产管理的智能方案 【免费下载链接】m4s-converter 一个跨平台小工具,将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 在数字内容瞬息万变的…...
Sunshine配置终极指南:从零开始打造完美游戏串流体验
Sunshine配置终极指南:从零开始打造完美游戏串流体验 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine Sunshine是一款强大的自托管游戏串流服务器,让你在任何…...
基于PSCAD的光伏-火电打捆直流送出系统建模与扰动特性仿真研究
基于PSCAD的光伏-火电打捆直流送出系统建模与扰动特性仿真研究 摘要 随着我国“双碳”目标的深入推进,以光伏为代表的新能源发电装机规模持续快速增长。然而,光伏发电具有间歇性和波动性特征,大规模并网对电力系统的安全稳定运行提出了严峻挑战。将光伏与火电打捆经高压直…...
Prometheus监控主机,Grafana成图
全部使用官方 GitHub 源的部署方案,下载链接来自官方,无需镜像。 官方下载地址汇总 组件 官方下载地址 Node Exporter https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz Prometheus https…...
终极指南:Awoo Installer - Nintendo Switch游戏安装的免费开源解决方案
终极指南:Awoo Installer - Nintendo Switch游戏安装的免费开源解决方案 【免费下载链接】Awoo-Installer A No-Bullshit NSP, NSZ, XCI, and XCZ Installer for Nintendo Switch 项目地址: https://gitcode.com/gh_mirrors/aw/Awoo-Installer 还在为Switch游…...
【2026年携程暑期实习- 5月10日-第四题-单数组交换】(题目+思路+JavaC++Python解析+在线测试)
题目内容 游游有两个长度同为 nnn 的整数数组 aaa 和 bbb。她会对数组...
微信单向好友终极检测指南:如何快速发现谁已悄悄删除或拉黑你
微信单向好友终极检测指南:如何快速发现谁已悄悄删除或拉黑你 【免费下载链接】WechatRealFriends 微信好友关系一键检测,基于微信ipad协议,看看有没有朋友偷偷删掉或者拉黑你 项目地址: https://gitcode.com/gh_mirrors/we/WechatRealFrie…...
为LLM构建持久化知识大脑:基于知识图谱与向量搜索的Memento MCP实战
1. 项目概述:为LLM构建一个持久化、可理解的知识大脑如果你用过Claude Desktop、Cursor或者GitHub Copilot,可能会发现一个痛点:这些AI助手虽然聪明,但它们的“记忆”是短暂的、碎片化的。每次对话都像是一次全新的邂逅࿰…...
