【结构型模式-代理模式】

news2024/9/8 22:54:42

概述

由于某些原因需要给某对象提供一个代理以控制该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象与目标对象之间的中介。
Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成,而动态代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。

结构

代理(Proxy)模式分为三种角色:

  • 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或拓展真实主题的功能。
    在这里插入图片描述
静态代理
package com.syn.proxy.static_proxy;

/*卖票规范*/
public interface SellTickets {
    void sell();
}

package com.syn.proxy.static_proxy;

/*火车站卖票*/
public class TrainStation implements  SellTickets{
    @Override
    public void sell() {
        System.out.println("火车站卖票.");
    }
}

package com.syn.proxy.static_proxy;

/*代理点*/
public class Proxypoint implements SellTickets{

    private TrainStation trainStation = new TrainStation();
    @Override
    public void sell() {
        System.out.println("代理收取费用.");
        trainStation.sell();
    }
}
package com.syn.proxy.static_proxy;

/*客户端买票*/
public class Client {
    public static void main(String[] args) {
        /*创建代理类*/
        Proxypoint proxypoint = new Proxypoint();
        /*买票*/
        proxypoint.sell();
    }
}

在这里插入图片描述

JDK动态代理
package com.syn.proxy.jdk_proxy;

/*卖票规范*/
public interface SellTickets {
    void sell();
}

package com.syn.proxy.jdk_proxy;

/*火车站卖票*/
public class TrainStation implements SellTickets {
    @Override
    public void sell() {
        System.out.println("火车站卖票.");
    }
}

package com.syn.proxy.jdk_proxy;

import com.syn.proxy.static_proxy.SellTickets;
import com.syn.proxy.static_proxy.TrainStation;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*获取代理对象的工厂类*/
public class ProxyFactory {
    /*声明目标对象*/
    private TrainStation trainStation = new TrainStation();

    public SellTickets getProxyObject(){
        /*返回代理对象*/
        SellTickets proxyObject  =  (SellTickets) Proxy.newProxyInstance(
                /*用于加载代理类,可以通过目标对象获取类加载器*/
                trainStation.getClass().getClassLoader(),
                /*代理类实现的接口字节码对象*/
                trainStation.getClass().getInterfaces(),
                /*代理对象的调用处理程序*/
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("代理收费(JDK动态版本).");
                        /*执行目标对象方法*/
                        Object object = method.invoke(trainStation,args);
                        return object;
                    }
                }
        );
        return proxyObject;
    }
}

package com.syn.proxy.jdk_proxy;

import com.syn.proxy.static_proxy.SellTickets;

public class Client {
    public static void main(String[] args) {
        /*创建代理工厂*/
        ProxyFactory proxyFactory = new ProxyFactory();
        /*使用工厂获取代理对象*/
        SellTickets proxyObject = proxyFactory.getProxyObject();
        /*调用目标方法*/
        proxyObject.sell();
    }
}

在这里插入图片描述

CDLIB动态代理

对于上面的案例,如果没有定义SellTickets接口,只定义了TrainStation。很显然JDK动态代理便无法使用了,因为JDK动态代理要求必须定义接口,对接口进行代理。
CGLIB是一个功能强大,高性能的代码生成包,它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。
需要引入maven包

    <dependencies>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.1</version>
        </dependency>
    </dependencies>
package com.syn.proxy.cglib_proxy;


/*火车站卖票*/
public class TrainStation{
    public void sell() {
        System.out.println("火车站卖票.");
    }
}

package com.syn.proxy.cglib_proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/*代理对象工厂*/
public class ProxyFactory implements MethodInterceptor {
    /*声明火车站对象*/
    private TrainStation trainStation = new TrainStation();

    public TrainStation getProxyObject(){
        /*创建Enhancer对象,类似于JDK代理中的Proxy类*/
        Enhancer enhancer = new Enhancer();
        /*设置父类的字节码对象*/
        enhancer.setSuperclass(TrainStation.class);
        /*设置回调函数*/
        enhancer.setCallback(this);
        /*创建代理对象*/
        return (TrainStation) enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理收费(CGLIB动态版本).");
        /*要调用目标对象的方法*/
       return method.invoke(trainStation,objects);
    }
}

package com.syn.proxy.cglib_proxy;

public class Client {
    public static void main(String[] args) {
        /*创建代理工厂对象*/
        ProxyFactory proxyFactory = new ProxyFactory();
        /*获取代理对象*/
        TrainStation proxyObject = proxyFactory.getProxyObject();
        /*调用代理对象的sell方法卖票*/
        proxyObject.sell();
    }
}

在这里插入图片描述

三种代理对比

  • jdk代理和CGLIB代理

使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在JDK1.6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的类或者方法进行代理,因为CGLib原理是动态生成被代理类的子类。
在JDK1.6、JDK1.7、JDK1.8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLib代理效率,只有当进行大量调用的时候,JDK1.6和JDK1.7比CGLib代理效率低一点,但是到JDK1.8的时候,JDK代理效率高于CGLib代理。所以如果有接口使用JDK动态代理,如果没有接口使用CGLIB代理。

  • 动态代理和静态代理

动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
如果接口增加一个方法,静态代理模式除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。而动态代理不会出现该问题。

优缺点

优点:

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

缺点:

  • 增加了系统的复杂度。

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

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

相关文章

Linux--网络设置

目录 一、测试网络连接 1、查看网络接口信息 1.1 ifconfig 命令---查看网络接口信息 1.1.1 ifconfig 网卡 #单独查看某个网卡 1.1.2 ifconfig -a #显示所有活动及非活动的连接 二、修改网络配置文件 三、设置网络接口参数 3.1 启用、禁用网络接口配置 3.2 hostn…

数据库数据恢复—SQL Server数据库由于存放空间不足报错的数据恢复案例

SQL Server数据库数据恢复环境&#xff1a; 某品牌服务器存储中有两组raid5磁盘阵列。操作系统层面跑着SQL Server数据库&#xff0c;SQL Server数据库存放在D盘分区中。 SQL Server数据库故障&#xff1a; 存放SQL Server数据库的D盘分区容量不足&#xff0c;管理员在E盘中生…

Python爬虫速成之路(1):获取网页源代码

hello hello~ &#xff0c;这里是绝命Coding——老白~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;绝命Coding-CSDN博客 &a…

LLM-阿里云 DashVector + ModelScope 多模态向量化实时文本搜图实战总结

文章目录 前言步骤图片数据Embedding入库文本检索 完整代码 前言 本文使用阿里云的向量检索服务&#xff08;DashVector&#xff09;&#xff0c;结合 ONE-PEACE多模态模型&#xff0c;构建实时的“文本搜图片”的多模态检索能力。整体流程如下&#xff1a; 多模态数据Embedd…

【python】QWidget父子关系,控件显示优先级原理剖析与应用实战演练

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

变位齿轮的齿高好像不变

通过这个软件的计算&#xff0c;变位尺寸的大小径都会同时变化&#xff0c;从而整个齿高好像没有变化。 下面百度答案

中国AI已遥遥领先

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 种种迹象表明&#xff0c;中国的AI产业是仅次于美国的存在&#xff0c;中国的AI已经遥遥领先&#xff0c;其他国家。 根据中国信息通信研究院发布的报告称&#xff1a; 根据中国信息通信研究院近日发布的《全球…

LabVIEW远程实验数据采集系统

随着科学研究的不断发展&#xff0c;实验室对远程数据采集和监控的需求越来越高。传统的数据采集方式往往需要实验人员亲临现场&#xff0c;费时费力&#xff0c;且数据实时性较差。为了解决这些问题&#xff0c;基于LabVIEW开发了一套远程实验数据采集系统&#xff0c;实现对实…

网络建设与运维23国赛网络运维正式赛题解析

竞赛环境请看主页&#xff01; 23国赛网络运维 任务描述&#xff1a;某集团公司在更新设备后&#xff0c;路由之间无法正常通信&#xff0c;请修 复网络达到正常通信。 &#xff08;1&#xff09; 请在server1“管理员”下拉菜单中选择“镜像”选项卡&#xff0c;点 击 “创…

就业平台小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;企业管理&#xff0c;企业类型管理&#xff0c;留言板管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;招聘信息&#xff0c;简历&#xff0c;我的…

centos安装数据库同步工具sqoop并导入数据,导出数据,添加定时任务

目录 1.安装jdk 1.1上传jdk安装包到/opt目录下并解压 1.2解压 1.3配置环境变量 2.安装hadoop 2.1.下载hadoop 2.2.解压hadoop 2.3配置环境变量 3.安装sqoop 3.1下载 3.2解压 3.3下载依赖包并复制到指定位置 3.3.1下载commons-lang-2.6-bin.tar.gz 3.3.2将mysql-c…

2024Q2全球PC市场:联想增3.7%、苹果增20.8%

7月9日&#xff0c;IDC发布最新PC市场报告&#xff0c;称2024年第2季度全球PC出货量 6490 万台&#xff0c;同比增长3.0%&#xff0c;尽管整体市场得益于与2023年较低数据的有利比较&#xff0c;但中国的PC市场仍处于疲软态势。除中国外&#xff0c;全球出货量同比增长超过5%。…

ubuntu部署minio集群

minio集群介绍 官方文档&#xff1a;https://min.io/docs/minio/linux/operations/install-deploy-manage/deploy-minio-multi-node-multi-drive.html 本方案采用在多节点多驱动器 (MNMD) 或“分布式”配置部署 MinIO。 MNMD 部署提供企业级性能、可用​​性和可扩展性&#…

【每日一练】python面对对象的基本概念和用法(附实例)

面向对象编程&#xff08;OOP&#xff09;是一种程序设计方法&#xff0c;其基本概念包括对象、类、继承和封装。 对象&#xff1a;对象是系统中的基本单位&#xff0c;用于描述客观事物。每个对象包含一组属性和对这些属性进行操作的方法。对象是类的一个实例&#xff0c;具有…

10-《木棉》

木 棉 木棉又名红棉、英雄树、攀枝花、斑芝棉、斑芝树、攀枝&#xff0c;属木棉科&#xff0c;落叶大乔木&#xff0c;原产印度。木棉是一种在热带及亚热带地区生长的落叶大乔木&#xff0c;高10&#xff0d;25米。树干基部密生瘤刺&#xff0c;以防止动物的侵入。木棉外观多变…

Dart笔记:Isolate及其通信机制

Dart笔记 多隔离及其通信机制 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/a…

【合并两个有序数组】

合并两个有序数组 一、题目二、普通解法三、双指针 一、题目 二、普通解法 先合并后排序 补充:js合并数组方法详见https://blog.csdn.net/ACCPluzhiqi/article/details/131702269?fromshareblogdetail js排序方法见http://t.csdnimg.cn/wVCOP 时间复杂度&#xff1a;O(mn)…

【DevOps】在云原生时代的角色与重要性探索

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是云原生 2、云原生的核心特性 3、什么是DevOps…

c++获取用户的输入并格式化

一行单个数据 string str; cin>>str;一行固定多个且空格隔开 int n, m; cin >> n >> m;在输入时&#xff0c;会自动做格式装换。 一行不固定多个且空格隔开 #include <sstream> #include <string>string str; getline(cin, str); stringstr…

FFmpeg开发笔记(四十五)使用SRT Streamer开启APP直播推流

SRT Streamer是一个安卓手机端的开源SRT协议直播推流框架&#xff0c;可用于RTMP直播和SRT直播。SRT Streamer支持的视频编码包括H264、H265等等&#xff0c;支持的音频编码包括AAC、OPUS等等&#xff0c;可谓功能强大的APP直播框架。 相比之下&#xff0c;另一款APP直播框架RT…