Java基础——代理模式

        代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

一、代理模式的主要作用

  • 控制访问:通过代理对象的方式间接地访问目标对象,防止直接访问对象给系统带来不必要的复杂性
  • 功能增强:通过代理业务对原有业务进行增强

二、代理的两种实现方式

1. 静态代理

        静态代理中,我们对目标对象的每个方法的增强都是手动完成的(后面会具体演示代码),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(需要对每个目标类都单独写一个代理类)。

实现步骤:

  1. 定义一个接口及其实现类;
  2. 创建一个代理类同样实现这个接口
  3. 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。

示例:定义三个类和一个接口

package proxy;
// 定制接口
public interface ByClothes {public abstract void clothes(String size);
}
package proxy;
/*** 销售类*/
public class Proxy implements ByClothes {private ClothesFactory clothesFactory = new ClothesFactory();@Overridepublic void clothes(String size) {FrontService();clothesFactory.clothes(size);endService();}//前置服务public void FrontService() {System.out.println("根据您的需求进行市场调研");}//前置服务public void endService() {System.out.println("为您提供一条龙的包办服务");}
}
package proxy;
// 工厂类
public class ClothesFactory implements ByClothes{public void clothes(String size){System.out.println("已经给您定制好了一件大小为"+size+"的衣服");}public void 机器处理(){}public void 原材料(){}
}
package proxy;
//测试类
public class Test {public static void main(String[] args) {Proxy proxy = new Proxy();proxy.clothes("xxxL");}
}

在工厂类中,我们定义了定制衣服的具体方法,还有机器处理和原材料两个方法,在代理类中,我们静态的创建了工厂类的实例对象,这个对象是代理类中的静态属性,只能由本类调用,通过这种方式实现了代理类的控制访问功能。

接口的作用则是对特定功能实现增强,我们可以看到工厂类中不止一种方法,如果想要指定调用定制衣服的方法,则需要接口的帮助,在接口中定义该方法,然后让实现类和代理类共同继承接口,则代理类和实现类都需要重写该方法,在测试类中调用代理类的定制方法,在代理类中的定制方法中调用实现类也就是工厂类的定制方法,同时在代理类的定制方法中添加其他的逻辑(功能增强)

2. 动态代理

        相比于静态代理来说,动态代理更加灵活。我们不需要针对每个目标类都单独创建一个代理类,并且也不需要我们必须实现接口,我们可以直接代理实现类( CGLIB 动态代理机制)。从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

假设我们现在再创建一个工厂用于定制鞋子,叫做ShootesFactory类,继续用静态代理方式的话,我们可以再创建一个定制鞋子的接口,让实现类ShootesFactory和代理类都去继承该接口

但是这种静态代理的方法实际使用时就会暴露它的缺点:调用不同的方法都需要在代理对象中创建对象,静态代理需要为每个被代理类都生成对应的代理类,在编译时需要处理大量的代码,这会导致编译时间增加,显然这种方法会降低开发的效率,基于此问题设计出了一种更为方便快捷的代理模式,也就是动态代理。

动态代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class DyProxy implements InvocationHandler {//被代理的对象//代理对象如何得知自己代理的是哪个目标类//这里这样写其实是让用户告诉我,我要代理谁private Object o ;public DyProxy(Object o){this.o = o;}//2.获取目标类的接口,要知道自己代理的核心方法是什么public Object getProxyInterFace(){return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(),this);}//知道了接口----》变相得知了自己要代理的核心方法://invoke方法是利用反射的方式获取到了要代理的核心方法//1.Object:jdk创建的代理类,无需赋值//2.Method:目标类当中的方法,jdk提供,无需赋值//3.Object[]:目标类当中的方法的参数,jdk提供,无需赋值@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {FrontService();method.invoke(o,args);endService();return null;}//前置服务public void FrontService() {System.out.println("根据您的需求进行市场调研");}//前置服务public void endService() {System.out.println("为您提供一条龙的包办服务");}}

在上述代码中,实现类是以代理对象构造器参数的形式传入的,在代理类中有获取目标类接口的方法,获取到目标类接口之后通过代理类中的invoke方法反射调用实现类中的invoke方法,这种方式有以下优点:

  • 动态代理的接口是靠根据目标类获取的,而在静态代理中是手动添加的
  • 动态代理在添加新的类时不需要改变本身代码

动态代理的应用场景

  • AOP(面向切面编程):动态代理是实现 AOP 的核心技术之一。通过动态代理,可以在不修改业务逻辑的情况下,将一些通用的横切关注点(如日志记录、事务管理、权限验证等)织入到业务方法中,提高代码的可维护性和可复用性。
  • 远程方法调用(RMI):在分布式系统中,动态代理可以用于实现远程方法调用。客户端通过代理对象调用远程服务的方法,代理对象负责处理网络通信和序列化等细节,使得客户端就像调用本地方法一样调用远程方法。
  • 缓存代理:可以使用动态代理实现缓存功能。在调用目标方法之前,先检查缓存中是否存在结果,如果存在则直接返回缓存结果,否则调用目标方法并将结果存入缓存。
比较静态代理动态代理
定义时机在编译期间就已经确定代理类和被代理类的关系,代理类的代码是手动编写或者通过工具生成的,在程序运行前就已经存在于代码中在程序运行时动态生成代理类和代理对象,无需手动编写代理类的代码,而是利用反射机制在运行时创建代理类的字节码并加载到 JVM 中
代码复杂度需要为每个被代理类手动创建对应的代理类,如果被代理类的方法较多,或者有多个被代理类,会导致代码量大幅增加,且存在大量重复代码,使代码变得臃肿,可维护性和可读性降低无需手动编写代理类,代码量相对较少,结构更简洁。尤其是在处理多个被代理类或方法时,优势更加明显,提高了代码的可维护性和开发效率
灵活性灵活性较差,当被代理类的接口发生变化(如增加、删除方法)时,代理类需要进行相应的修改。同时,代理逻辑在编译时就已经确定,运行期间无法动态调整具有很高的灵活性,可以在运行时根据需要动态地为不同的目标对象创建代理对象,并且可以动态调整代理逻辑。即使被代理类的接口发生变化,也不需要修改代理类的代码
可扩展性可扩展性受限,当需要为代理类添加新的功能时,可能需要在多个代理类中都进行修改,工作量大且容易出错易于扩展,通过修改调用处理器(如 JDK 动态代理的 InvocationHandler 或 CGLIB 动态代理的 MethodInterceptor)的逻辑,就可以方便地为代理对象添加新的功能,无需修改大量代码
性能由于代理类和被代理类的关系在编译时就已经确定,方法调用直接指向代理类的方法,因此在方法调用时性能较高,没有额外的反射开销在创建代理对象时,需要利用反射机制生成代理类的字节码并加载到 JVM 中,创建过程有一定性能开销。在方法调用时,JDK 动态代理使用反射调用目标方法,也会带来一定的性能损耗;不过 CGLIB 动态代理通过继承实现,方法调用性能相对较好
适用场景适用于被代理类数量较少、接口稳定且不需要频繁修改代理逻辑的场景适用于需要在运行时动态改变代理逻辑、处理多个不同类型的被代理对象,或者实现 AOP 等场景

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/21034.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微软宣布 Windows 11 将不再免费升级:升级需趁早

大家都知道如果你现在是Windows 10 系统,其实可以免费升级到正版 Windows 11,只要你的电脑配置满足 TPM2.0要求。 而最近微软已经公布了 Windows 10 的最后支持时间,也就是今年10月14日,在这之后微软将不再对Windows 10负责&#…

django连接mysql数据库

1.下载mysqlclient第三方库 2.在settings.py里连接数据库(提前建好) DATABASES {default: {ENGINE: django.db.backends.mysql,NAME: 学生信息,USER: root,PASSWORD: 999123457,HOST: localhost,POST: 3306,} } 3.在models.py里创建一个类&#xff0…

滤波器 | 原理 / 分类 / 特征指标 / 设计

注:本文为 “滤波器” 相关文章合辑。 未整理去重。 浅谈滤波器之 —— 啥是滤波器 原创 RF 小木匠 射频学堂 2020 年 03 月 25 日 07:46 滤波器,顾名思义,就是对信号进行选择性过滤,对不需要的信号进行有效滤除。按照其传输信…

v4l2子系统学习(一)V4L2应用程序编程

文章目录 1、声明2、前言3、数据采集流程3.1、buffer的管理3.2、完整的使用流程 4、应用程序编写5、测试 1、声明 本文是在学习韦东山《驱动大全》V4L2子系统时,为梳理知识点和自己回看而记录,全部内容高度复制粘贴。 韦老师的《驱动大全》&#xff1a…

NAC网络接入控制三种认证方式802.1X认证、MAC认证和Portal认证

NAC网络接入控制三种认证方式802.1X认证、MAC认证和Portal认证 1.NAC简介2.802.1X认证3. MAC认证4. Portal认证 1.NAC简介 NAC(Network Access Control)称为网络接入控制,通过对接入网络的客户端和用户的认证保证网络的安全,是一…

vscode远程报错:Remote host key has changed,...

重装了Ubuntu系统之后,由20.04改为22.04,再用vscode远程,就出现了以上报错。 亲测有效的办法 gedit ~/.ssh/known_hosts 打开这个配置文件 删掉与之匹配的那一行,不知道删哪一行的话,就打开第一行这个 /.ssh/confi…

多个 JDK 版本(Java 8、Java 17、Java 21)下载和切换

文章目录 多个 JDK 版本(Java 8、Java 17、Java 21)下载和切换1. 下载 JDK2. 配置环境变量3. JDK 版本切换4. 测试5. 在 IDEA 中切换 JDK注意: 多个 JDK 版本(Java 8、Java 17、Java 21)下载和切换 随着 Spring Boot …

深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作

一、问题背景(传统爬虫的痛点) 数据采集是现代网络爬虫技术的核心任务之一。然而,传统爬虫面临多重挑战,主要包括: 反爬机制:许多网站通过检测请求头、IP地址、Cookie等信息识别爬虫,进而限制…

【Vue+python】Vue调用python-fastApi接口实现数据(数值、列表类型数据)渲染

前言:之前做的一直都是SpringBootVue的应用,但现在需要实现一个能将python实现的算法应用展示在前端的界面。想法是直接Vue调用python-fastApi接口实现数据渲染~ 文章目录 1. 变量定义2. axios调用python3. 跨域问题解决4. 数据渲染4.1 数值数据渲染4.2 …

SOME/IP--协议英文原文讲解8

前言 SOME/IP协议越来越多的用于汽车电子行业中,关于协议详细完全的中文资料却没有,所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块: 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 4.2 Speci…

禁止WPS强制打开PDF文件

原文网址:禁止WPS强制打开PDF文件_IT利刃出鞘的博客-CSDN博客 简介 本文介绍如何避免WPS强制打开PDF文件。 方法 1.删除注册表里.pdf的WPS绑定 WinR,输入:regedit,回车。找到:HKEY_CLASSES_ROOT\.pdf删除KWPS.PDF…

Pytorch深度学习教程_3_初识pytorch

欢迎来到《PyTorch深度学习教程》系列的第三篇!在前面的两篇中,我们已经介绍了Python及numpy的基本使用。今天,我们将深入探索PyTorch的核心功能,帮助你更好地理解和使用这个强大的深度学习框架。 欢迎订阅专栏: 深度…

Windows桌面系统管理5:Windows 10操作系统注册表

Windows桌面系统管理0:总目录-CSDN博客 Windows桌面系统管理1:计算机硬件组成及组装-CSDN博客 Windows桌面系统管理2:VMware Workstation使用和管理-CSDN博客 Windows桌面系统管理3:Windows 10操作系统部署与使用-CSDN博客 Wi…

web入侵实战分析-常见web攻击类应急处置实验1

场景说明: 某天运维人员发现在/opt/tomcat8/webapps/test/目录下,多出了一个index_bak.jsp这个文件, 并告诉你如下信息 操作系统:ubuntu-16.04业务:测试站点中间件:tomcat开放端口:22&#x…

Bio-ORACLE数据分享[decade 2010-2020] [Surface layers]

Bio-ORACLE数据分享[decade 2010-2020] [Surface layers] 文章目录 Bio-ORACLE数据分享[decade 2010-2020] [Surface layers]前言一、文件分享(主要)二、相关代码(选看)总结 Bio-ORACLE数据分享[decade 2010-2020] [Surface layer…

换服务器需要做的工作(记录一下)

1.Nginx开启OCSP 加快Let’s Encrypt免费证书 HTTPS网站访问速度 https://blog.csdn.net/wx23986/article/details/141722669 2.添加伪静态规则 location / {rewrite ^([^\.]*)/topic-(.)\.html$ $1/portal.php?modtopic&topic$2 last;rewrite ^([^\.]*)/article-([0-9…

c++作业

练习题&#xff1a; #include <iostream> #include <cstring> using namespace std;class mystring {char* p;int len; public:mystring();mystring(const char* p);~mystring();void copy(const mystring& str);void append(const mystring& str);void sh…

网络爬虫学习:借助DeepSeek完善爬虫软件,实现模拟鼠标右键点击,将链接另存为本地文件

一、前言 最近几个月里&#xff0c;我一直在学习网络爬虫方面的知识&#xff0c;每有收获都会将所得整理成文发布&#xff0c;不知不觉已经发了7篇日志了&#xff1a; 网络爬虫学习&#xff1a;从百度搜索结果抓取标题、链接、内容&#xff0c;并保存到xlsx文件中 网络爬虫学…

leetcode203.移除链表元素

目录 问题描述示例提示 具体思路思路一思路二 代码实现 问题描述 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 题目链接&#xff1a;移除链表元素 示例 提示 列表中的节点数目在范围…

全球直播新标杆:DeepSeek融合全平台AI无人直播,构建直播流量永动机!

全球直播新标杆&#xff1a;DeepSeek融合全平台AI无人直播&#xff0c;构建直播流量永动机&#xff01; 在科技日新月异的今天&#xff0c;直播行业正经历一场前所未有的变革。在这场变革中&#xff0c;DeepSeek凭借其创新的AI无人直播系统&#xff0c;正逐步树立起全球直播的新…