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

静态代理和动态代理的区别以及实现过程

前言

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

在这里插入图片描述
其实代理模式的核心思想就是这么简单,在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.Proxyjava.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汽车示波器产品模型 全流程专业讲解的视频资料 产品功能和应用场景 全面详细的产品手册 还有虹科首席技术工程师在线连麦答疑!!&#xf…...

4.数据类型-字符串【Python】

文章目录字符串索引切片转义字符格式化符号f-string字符串操作判断&检测转换剪切&填充拼接统计格式转化练习字符串 ​ 字符串是 Python 中最常用的数据类型。可以使用单引号,双引号,3对双引号创建一个字符串。Python 中没有单独的字符类型 char…...

搞量化先搞数(上):A股股票列表免费抓取实战

到了这一步,我们学习了基础的爬虫请求库urllib和requests,尤其是后者,强大且易用,极其适合新手使用。那么今天我们就找一个相对简单的案例,来看一下如何在实战中应用爬虫技能。 相信很多朋友都对股票感兴趣,甚至有些朋友想要通过量化研究来获得超额收益。然而,想要进行…...

SpringCloud-负载均衡Ribbon

一、配置使用1、添加依赖&#xff08;该依赖包含在eureka-client依赖中&#xff09;<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency>2、在RestTemp…...

Linux入门篇(二)

Linux前言链接文件符号链接&#xff08;软链接&#xff09;硬链接shellshell 的类型shell的父子关系理解外部命令和内建命令外部命令内建命令Linux环境变量PATH环境变量前言 在这一章&#xff0c;我对Linux中有关shell较为深入的理解和环境变量方面知识的一个记录。同时&#x…...

第四部分:特殊用途的句子——第三章:虚拟

虚拟语气 1、什么是虚拟&#xff1f; 虚拟就是非真实。换句话说&#xff0c;这事不是真的&#xff0c;这事不太可能成真&#xff0c;非真实&#xff0c;就是虚拟 2、怎么表示虚拟&#xff1f; 英语是一个典型的形式来补充内容的语言&#xff0c;若要表达虚拟&#xff0c;只…...

Java中如何获取泛型类型信息

文章目录声明侧泛型使用侧泛型获取泛型类型相关方法1. Class类的泛型方法2. Field类的泛型方法3. Method类的泛型方法4. ParameterizedType类获取声明侧的泛型类型信息获取使用侧的泛型类型信息匿名内部类实现获取使用侧的泛型类型根据使用泛型位置的不同可以分为&#xff1a;声…...

【云原生】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语言指针

指针 指针是存放地址的变量&#xff0c;也可以说指针地址。 对于定义p&#xff08;这里的话&#xff0c;只是定义&#xff0c;说明p是指针&#xff09;&#xff0c;p作为一个指针去指向存放数据的位置&#xff0c;而p意思是取&#xff08;p指向的内存位置的数据&#xff09;&…...

5.33 综合案例2.0 -ESP32拍照上传阿里云OSS

综合案例2.0 - ESP32拍照上传阿里云OSS案例说明连线功能实现1.阿里云平台连接2.OSS对象存储服务3.ESP32-CAM开发环境4.代码ESP32-CAM开发板代码HaaS506开发板代码测试数据转图片方法案例说明 使用ESP32拍照,将照片数据上传阿里云OSS&#xff08;通过4G网络上传&#xff09;。 …...

java无重复字符的最长子串

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输入: s “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “…...

测试用例设计工作中的应用

1. 等价类划分 常见的软件测试面试题划分等价类: 等价类是指某个输入域的子集合.在该子集合中,各个输入数据对于揭露程序中的错误都是等效的.并合理地假定:测试某等价类的代表值就等于对这一类其它值的测试.因此,可以把全部输入数据合理划分为假设干等价类,在每一个等价类中取一…...

leetcode 困难 —— 数字 1 的个数(简单逻辑题)

&#xff08;害&#xff0c;做题是真的慢&#xff0c;这面试给我这题我估计就傻了&#xff09; 题目&#xff1a; 给定一个整数 n&#xff0c;计算所有小于等于 n 的非负整数中数字 1 出现的个数。 题解&#xff1a; 首先看看整数范围 0 < n < 10^9 不能遍历&#xff0…...

关于JSON

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> </head> <body> <script> /* 1、JSON的英文全称&#xff1a;Java…...

Apifox-接口调用、自动化测试工具

Apifox简介 Apifox 的定位是Postman Swagger Mock JMeter&#xff0c;具有API文档管理、API调试、API Mock、API 自动化测试等功能。可以通过一种工具解决之前使用多种工具的数据同步问题。高效、及时、准确&#xff01; 安装 Apifox的安装非常方便&#xff0c;直接下载安…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...