Java设计模式中代理模式是什么/JDK动态代理分为哪些,静态代理又怎么实现,又适合哪些场景

news2024/12/24 8:40:07

继续整理记录这段时间来的收获,详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用!

5.结构型模式

5.1 概述

  • 根据如何将类或对象按某种布局组成更大的结构,分为类结构模式对象结构模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象
  • 对象结构模式比类结构模式具有更大灵活性—因组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”

5.2 代理模式

5.2.1 概述

  • 背景:由于某些原因需要给某对象提供一个代理以控制对该对象的访问
  • 特点:访问对象不适合或者不直接引用目标对象,代理对象作为可以访问对象和目标对象的中介
  • 根据代理类生成时机不同分为静态代理和动态代理,静态代理在编译器生成,后者在Java运行时动态生成
  • 动态代理分为JDK代理和CGLIB代理

5.2.2 结构

  • 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法
  • 真实主题(Real Subject)类:实现抽象主题类的具体业务,是代理对象所代表的真实对象
  • 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,可以访问,控制或扩展真实主题的功能

5.2.3 静态代理

火车站卖票案例
代码:

//抽象主题
public interface SellTickets {  
    void sellTickets();  
}
//真实主题
public class TrainStation implements SellTickets{  
    @Override  
    public void sellTickets() {  
        System.out.println("火车站卖票");  
    }  
}
//代理类
public class ProxyPoint implements SellTickets{  
    private TrainStation station = new TrainStation();  
    @Override  
    public void sellTickets() {  
        System.out.println("代理商收取服务费");  
        station.sellTickets();  
    }  
}

5.2.4 JDK动态代理

5.2.4.1 案例

  • 使用案例同上
  • 抽象主题和真实主题同上
  • 代码

    注意:
    ProxyFactory不是代理模式中的代理类
public class ProxyFactory{  
//    声明目标对象  
    private TrainStation station = new TrainStation();  
    public SellTickets getProxyObjects()  
    {  
        /*ClassLoader loader, 类加载器,用于加载代理类,可以通过目标对象获取类加载器  
         Class<?>[] interfaces,代理类实现的接口的字节码对象  
         InvocationHandler h 代理对象调用的调用处理程序  
        * */        SellTickets proxyInstance = (SellTickets) Proxy.newProxyInstance(  
                station.getClass().getClassLoader(),  
                station.getClass().getInterfaces(),  
                new InvocationHandler() {  
                    /*Object 代理对象,和proxyInstance是同一个对象,在invoke中基本不用  
                    Method 代理对象调用方法,对接口中方法进行封装的对象,这里是sellTickets  
                    Object[] 调用方法参数  
                    * */                    @Override  
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
                        System.out.println("代理商收取服务费(JDK动态代理)");  
//                        执行目标对象的方法  
                        Object invoke = method.invoke(station, args);  
                        return invoke;  
                    }  
                }  
        );  
        return proxyInstance;  
    }  
}
	//测试
	 public static void main(String[] args) {  
//        获取代理对象  
//         创建代理工厂对象  
        ProxyFactory proxyFactory = new ProxyFactory();  
//        使用代理工厂创建代理对象  
        SellTickets proxyObjects = proxyFactory.getProxyObjects();  
//        调用买票方法  
        proxyObjects.sellTickets();  
    }

5.2.4.2 案例中的代理类

  • 使用arthas-boot.jar来查看具体的代理类等信息
  • 解压后使用CMD打开
    • 在测试类加代码使程序一直运行,如图![[Pasted image 20221231154138.png]]
    • 命令java -jar arthas-boot.jar,如图![[Pasted image 20221231154030.png]]
    • 继续输入2,如图![[Pasted image 20221231154059.png]]
    • 命令com.sun.proxy.$Proxy0,如图![[Pasted image 20221231154338.png]]
    • 代理类$Proxy0重点代码
    public final class $Proxy0 extends Proxy implements SellTickets {  
    private static Method m3;  
    public $Proxy0(InvocationHandler invocationHandler) {  
        super(invocationHandler);  
    }  
    static {  
        m3 = Class.forName("com.demo.patternDesign.ProxyModel.DynamicJDKProxy.SellTickets").getMethod("sellTickets", new Class[0]);  
    } 
    

// 代理类调用真实对象方法
public final void sellTickets() {
this.h.invoke(this, m3, null);
}
}
```

  • 执行流程
    • 测试类通过代理对象调用sell方法
    • 根据多态,执行代理类$Proxy0的sell方法
    • 代理类$Proxy0的sell方法又调用InvocationHandle接口中的自实现类对象的invoke方法(测试类加收取服务费那方法)
    • invoke方法通过反射执行真实对象类TrainStation中的sell方法

5.2.5 CGLIB动态代理

和之前一样的案例

  • CGLIB包坐标,CGLIB下载,关联包ASM下载
<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.3.0</version>
</dependency>
  • CGLIB包介绍:高性能代码生成包,可为没有实现接口类提供代理
  • 代码
// 代理工厂
public class ProxyFactory implements MethodInterceptor {  
//    创建真实对象  
    private TrainStation trainStation = new TrainStation();  
    public TrainStation getProxyObject(){  
//        创建Enhance对象,类似于JDK代理中的Proxy类  
        Enhancer enhancer = new Enhancer();  
//        设置父类的字节码对象  
        enhancer.setSuperclass(TrainStation.class);  
        设置回调函数  
        enhancer.setCallback(this);  
//        创建代理对象  
        TrainStation proxyObject = (TrainStation) enhancer.create();  
        return proxyObject;  
    }  
    @Override  
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {  
        System.out.println("代理商收取服务费(cglib代理)");  
        Object invoke = method.invoke(trainStation,objects);  
        return invoke;  
    }  
}
// 测试代码
    public static void main(String[] args) {  
//        创建代理工厂对象  
        ProxyFactory proxyFactory = new ProxyFactory();  
//        获取代理对象  
        TrainStation proxyObject = proxyFactory.getProxyObject();  
        proxyObject.sellTickets();
    }

5.2.6 3 种方式对比

5.2.6.1 JDK和CGLIB

  • CGLIB代理
    • 底层采用ASM字节码生成框架,使用字节码技术生成代理类
    • 不能对声明为final的类或方法进行代理,因CGLIB原理是动态生成被代理的子类
    • JDK1.6之前比JAVA使用反射效率要高
  • 两者效率问题
    • JDK1.6,1.7,1.8后在调用次数较少情况下JDK代理效率高于CGLIB代理效率
    • 仅当进行大量调用且在JDK1.6,1.7中CGLIB代理效率高
  • 选择:有接口使用JDK动态代理,没有接口使用CGLIB代理

5.2.6.2 动态和静态

  • 动态优点:声明的所有方法都被转移到调用处理器一个集中方法处理
  • 静态缺点:若接口增加方法,静态代理除了所有实现类需要实现此方法外,所有处理类也需要实现此方法,增加代码冗余与复杂性

5.2.7 优缺点

5.2.7.1 优点

  • 在客户端与目标对象之间起一个中介作用和保护目标对象作用
  • 可以扩展目标对象的功能
  • 能将客户端与目标对象分离,一定程度上降低系统耦合度

5.2.7.2 缺点

增加系统复杂度

5.2.8 使用场景

5.2.8.1 远程(Remote)代理

本地服务通过网络请求远程服务:可将网络通信部分隐藏,只保留本地服务一个接口,使其通过此接口访问远程服务提供功能,而不必过多关心通信细节。

5.2.8.2 防火墙(Firewall)代理

将浏览器配置成代理模式,防火墙将请求转发给互联网,当互联网响应时,代理服务器将信息再转发给浏览器

5.2.8.3 保护(Protect or Access)代理

控制一个对象访问,若需要,可以给不同对象以不同访问权限

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视频序列对比学习

前言 视频embedding化也即表征有很多实际的应用场景&#xff0c;比如文本-视频 pair的检索等等。由于视频一般来说较长&#xff0c;所以对于给定的一段话&#xff0c;其中的某些sentence句子一般对应着视频中某几个clip片段&#xff0c;之前常规的做法都是去匹配所有的sentence…

人工服务、人工智能和分析是联络中心的主要趋势

数字联络中心提供商 IPI 宣布了其对 2023 年的预测。IPI 非常重视提供卓越的客户联系&#xff0c;认为未来一年将由以下趋势定义&#xff1a;专注于人工服务&#xff1b;增加对人工智能和自动化的采用&#xff1b;以及更多地使用数据和分析。 关注人性化服务 据 IPI 称&#…

实现QTreeView、QTableView子项中的复选框勾选/取消勾选功能

1.前言本博文所说的技术点适用于同时满足下面条件的所有视图类&#xff1a;模型类从 QAbstractItemModel派生。代理类从QStyledItemDelegate派生。故本博文所说的技术点也适用于QTableView。2.需求提出基于Qt的model/view framework技术&#xff0c;利用QTreeView树视图实现业务…

【异常】SpringSecurity登录失败:Full authentication is required to access this resource

一、报错提示 SpringSecurity提示如下内容&#xff1a; 2023-01-07 06:08:51.843 [cdi-ids-commonprovider] [http-nio-9092-exec-14] WARN com.desaysv.tsp.logic.ids.config.MyAuthenticationEntryPoint - 登录失败&#xff1a;Full authentication is required to acces…

基于Java+Jsp+SpringMVC漫威手办商城系统设计和实现

基于JavaJspSpringMVC漫威手办商城系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联…

2023 年值得关注的 7 大人工智能 (AI) 技术趋势

&#x1f482; 个人网站:【海拥】【摸鱼游戏】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 人工智能 (AI) 已经接…

图数据库Neo4j实战(全网最详细教程)

1.图数据库Neo4j介绍 1.1 什么是图数据库&#xff08;graph database&#xff09; 随着社交、电商、金融、零售、物联网等行业的快速发展&#xff0c;现实社会织起了了一张庞大而复杂的关系网&#xff0c;传统数据库很难处理关系运算。大数据行业需要处理的数据之间的关系随数…

《Go 并发数据结构和算法实践》学习笔记 Day 1

极客时间21天打卡活动&#xff1a;2023.1.16-2.5 链表的接口&#xff1a; 插入元素删除元素读取元素 并发化改造&#xff1a; 并发插入元素并发删除元素并发读取元素 锁&#xff0c;每个节点都定义一把锁。 并发插入 区域猜想&#xff1a;如果某个CPU 锁定了某个节点&…

U3D客户端框架(资源管理篇)之资源热更新管理器 ResourceManager

一、资源热更新管理器模块设计 1.热更新是什么&#xff1f; 游戏或者软件内的 美术/脚本代码等资源 发生变化时&#xff0c;无需下载客户端重新进行安装&#xff0c;而是在应用程序启动的情况下&#xff0c;通过比对本地资源与CDN资源的MD5码&#xff0c;如果本地资源与CDN中…

Visual Code 打开方式添加到右键菜单

一、配置右键打开 文件 注册表找到分支&#xff1a; 计算机\HKEY_CLASSES_ROOT\*\shell 在这个里面 shell 分支里右键添加项 VisualCode&#xff08;这个可以随便起&#xff0c;便于识别就行&#xff09; 在 VisualCode 分支里右键添加项 Command&#xff08;必须这个名&am…

【C++】双指针用法

快慢指针/同向指针 [0,i)的数据代表处理好的数据[i,j)的数据是那些处理过但不需要的数据[j,array.length)区间的数据为接下来待处理的数据。 以上三个区间的开和闭需要根据题目要求定义&#xff0c;但是要保持一致。 用此方法处理过的数组&#xff0c;处理好的数据相对位置会保…

(mysql)Waiting for table metadata lock

MySQL5.5 中引入了 metadata lock. 顾名思义&#xff0c;metadata lock 不是为了保护表中的数据的&#xff0c;而是保护 database objects(元数据)的。包括表结构、schema、存储过程、函数、触发器、mysql的调度事件(events). 要理解 metadata lock 最重要的一点就是&#xff1…

python连接mysql之PyMySQL的基本使用

一、PyMySQL的基本使用使用pymysql 直接连接mysqlPyMySQL安装pip3 install pymysqlimport pymysql# 连接数据库&#xff0c;创建连接对象connection # 连接对象作用是&#xff1a;连接数据库、发送数据库信息、处理回滚操作&#xff08;查询中断时&#xff0c;数据库回到最初状…

关于Docker如何安装nginx

目录 1.Nginx 1.2. 安装nginx 2.容器之间相互通信 2.1.两个容器在同一网段 2.2.两个容器在不同网段 1.Nginx Nginx也是一款服务器&#xff0c;我们常用它做如&#xff1a;反向代理、负载均衡、动态与静态资源的分离的工作 反向代理&#xff1a;反向代理&#xff08;Revers…

java spring下载步骤

首先 我们要下载一下 spring 我们访问spring的官网 地址非常的好记 spring.io project进入官网我们选择 project>Spring Framework 进入界面 我们选择 Learn 下面就会给我们列举出版本 这边建议大家下5.3.24 首先 要下GA的 因为这表示它比较稳定 其次 版本比较适中 大部分…

黑客动态播报 | 2023年网络攻击趋势

今天是跨入2023年大门的第一个工作日,作为开年的第一篇内容,我们从安全说起。      自2020年勒索软件攻击呈爆发式增长以来,全球企业都经历了“噩梦”般的三年,层出不穷的手段和无孔不入的方式,都让我们绷紧了每一条神经。      而在这三年里,我们并不是疲于应对,通过不…

过年了,怎么样批量爬取某东商品信息,并做可视化

前言 马上就要过年了&#xff0c;大家都在屯年货了网络上商品信息太多&#xff0c;不知道如何选择&#xff0c;今天&#xff0c;我们就用python爬取商品信息&#xff0c;并做可视化。 环境使用 python 3.9pycharm 模块使用 requestsseleniumtime谷歌驱动 说明 一、谷歌驱动…

前端学习之BootStrap

前言 Bootstrap 最初是由 mdo 和 fat 于 2010 年中旬创造就职于 Twitter 时创造的。在成为开源框架之前&#xff0c;Bootstrap 被称为 Twitter Blueprint。经过几个月的开发&#xff0c;Twitter 举办了首届黑客周&#xff08;Hack Week&#xff09;&#xff0c;该项目获得了爆…

基于Java+SpringBoot+vue+elementUI私人健身教练预约管理系统设计实现

基于JavaSpringBootvueelementUI私人健身教练预约管理系统设计实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留…

Linux中的文件描述符

目录 文件描述符 系统调用 open 为什么fd从3开始呢&#xff1f; 为什么是0,1,2,3...呢&#xff1f; 文件描述符分配规则 系统调用 close 系统调用 wirte 系统调用 read 文件描述符 在了解文件描述符之前&#xff0c;先了解关于操作文件的系统调用&#xff0c;C语言中的f…