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

概述

由于某些原因需要给某对象提供一个代理以控制该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象与目标对象之间的中介。
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)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
如果接口增加一个方法,静态代理模式除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。而动态代理不会出现该问题。

优缺点

优点:

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

缺点:

  • 增加了系统的复杂度。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

手撸俄罗斯方块(五)——游戏主题

手撸俄罗斯方块&#xff08;五&#xff09;——游戏主题 当确定游戏载体&#xff08;如控制台&#xff09;后&#xff0c;界面将呈现出来。但是游戏的背景色、方块的颜色、方框颜色都应该支持扩展。 当前游戏也是如此&#xff0c;引入了 Theme 的概念&#xff0c;支持主题的扩…

ADS基础教程24 - Gerber文件的导入

EM介绍 一、引言二、基本概念1.仿真文件下载2.仿真文件介绍 二、导入步骤1.新建workspace2.选择Layout结构3.导入设计4.选择文件类型5.导入文件6.预览文件内容7.铜皮离散问题 四、总结 一、引言 本章节开始介绍在ADS中进行PCB仿真&#xff0c;首先讲解如何将Gerber文件导入到A…

顺序结构 ( 四 ) —— 标准数据类型 【互三互三】

序 C语言提供了丰富的数据类型&#xff0c;本节介绍几种基本的数据类型&#xff1a;整型、实型、字符型。它们都是系统定义的简单数据类型&#xff0c;称为标准数据类型。 整型&#xff08;integer&#xff09; 在C语言中&#xff0c;整型类型标识符为int。根据整型变量的取值范…

【RHCE】基于用户认证和TLS加密的HTTP服务(HTTPS)

目录 一、创建用户账号 二、TLS加密 三、配置http服务子配置文件 四、创建访问http服务的文件夹以及输入重定向到文件 五、配置Linux本地仓库以及Windows下的本地仓库 六、基础操作 七、测试 一、创建用户账号 用户认证 # 创建两个账户 [rootlocalhost ~]# htpasswd -…

YOLOv10改进 | 损失函数篇 | SlideLoss、FocalLoss、VFLoss分类损失函数助力细节涨点(全网最全)

一、本文介绍 本文给大家带来的是分类损失 SlideLoss、VFLoss、FocalLoss损失函数&#xff0c;我们之前看那的那些IoU都是边界框回归损失&#xff0c;和本文的修改内容并不冲突&#xff0c;所以大家可以知道损失函数分为两种一种是分类损失另一种是边界框回归损失&#xff0c;…

【安全设备】数据库审计

一、什么是数据库审计 数据库审计&#xff08;简称DBAudit&#xff09;是一种以安全事件为中心&#xff0c;实时记录网络上的数据库活动&#xff0c;并对数据库操作进行细粒度审计的合规性管理技术。它通过对用户访问行为的记录、分析和汇报&#xff0c;帮助用户事后生成合规报…

一套基于 Ant Design 和 Blazor 的开源企业级组件库

前言 今天大姚给大家分享一套基于Ant Design和Blazor的开源&#xff08;MIT License&#xff09;、免费的企业级组件库&#xff08;喜欢Ant Design风格的同学推荐使用&#xff09;&#xff1a;Ant Design Blazor。 项目特性 提炼自企业级中后台产品的交互语言和视觉风格。 开…

Codeforces Round #956 (Div. 2) and ByteRace 2024 E. I Love Balls(概率期望)

题目 思路来源 官方题解 题解 特殊球不会改变普通球的顺序&#xff0c;所以都是alice拿一半里较多的部分 n-k1一半向上取整就是(n-k2)/2&#xff0c;同理n-k个一般向上取整(n-k1)/2 每个特殊球独立地来看&#xff0c;在每个空隙的概率相同 所以分别统计特殊球和非特殊球的…

《Windows API每日一练》9.1.5 自定义资源

自定义资源&#xff08;Custom Resources&#xff09;是在 Windows 程序中使用的一种资源类型&#xff0c;用于存储应用程序特定的数据、图像、音频、二进制文件等。通过自定义资源&#xff0c;开发者可以将应用程序所需的各种资源文件集中管理和存储&#xff0c;便于在程序中访…

华为HCIP Datacom H12-821 卷34

1.单选题 防火墙默认已经创建了一些安全区域,以下哪一个安全区域不是防火墙上默认存在的? A、Trust B、DMZ C、Internet D、Local 正确答案&#xff1a; C 解析&#xff1a; 防火墙默认情况下为我们提供了三个安全区域&#xff0c;分别是 Trust、DMZ和Untrust 2.判断题 …

【RHCE】实验(HTTP,DNS,SELinux,firewalld的运用)

一、题目 二、主服务器配置 1.下载HTTP服务&#xff0c;DNS服务 [rootlocalhost ~]# yum install -y httpd bind 2.开启防火墙&#xff0c;放行服务 # 开启防火墙 [rootlocalhost ~]# systemctl start firewalld # 放行服务 [rootlocalhost ~]# firewall-cmd --add-service…

日常学习-20240710

1、一次一千万条数据插入和删除案例&#xff1a; 第一次&#xff1a;插入--批量插入&#xff0c;每次插入5000条数据&#xff0c;总耗时28min,数据无异常 删除--通过sql语句一次性删除&#xff0c;总耗时1h52min;一次删除的数据过多导致mysql的备份恢复文件极其庞大&#xff0…

在CentOS7虚拟机上使用Ollama本地部署Llama3大模型中文版+Open WebUI

一、创建虚拟机 1.1按照常规的CentOS教程来安装就行&#xff0c;我用的是以下版本&#xff1a; VMware版本&#xff1a;VMware Workstation Full v12.1.0-3272444 中文正式版 镜像版本&#xff1a;CentOS-7-x86_64-DVD-2009 1.2虚拟机配置参数&#xff0c;如下&#xff1a; 二…

彩虹小插画:成都亚恒丰创教育科技有限公司

彩虹小插画&#xff1a;色彩斑斓的梦幻世界 在繁忙的生活节奏中&#xff0c;总有一抹温柔的色彩能悄然触动心弦&#xff0c;那就是彩虹小插画带来的梦幻与宁静。彩虹&#xff0c;这一自然界的奇迹&#xff0c;被艺术家们巧妙地融入小巧精致的插画之中&#xff0c;不仅捕捉了瞬…

Camera Raw:直方图

Camera Raw 的直方图 Histogram面板不仅提供了照片亮度和色彩分布信息&#xff0c;还具备多项实用功能&#xff0c;辅助评估和调整照片。 ◆ ◆ ◆ 直方图的构成 直方图是一个二维坐标系统&#xff0c;横坐标表示不同程度的像素亮度&#xff0c;从左到右通常对应的是 0 ~ 255…

14-60 剑和诗人34 - Kubernetes 是部署 LLM 的首选平台

​​​​ 介绍 近年来&#xff0c;大型语言模型 (LLM) 一直在彻底改变自然语言处理领域。从 GPT-3 到 PaLM 等&#xff0c;这些模型可以生成类似人类的文本、回答问题、总结文档等等。然而&#xff0c;训练和部署 LLM 需要大量的计算。随着这些模型的规模和能力不断增长&#…

three完全开源扩展案例01-三角形渐变

演示地址 import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls.jsconst box document.getElementById(box)const scene new THREE.Scene()const camera new THREE.PerspectiveCamera(75, box.clientWidth / box.client…

Golang | Leetcode Golang题解之第227题基本计算器II

题目&#xff1a; 题解&#xff1a; func calculate(s string) (ans int) {stack : []int{}preSign : num : 0for i, ch : range s {isDigit : 0 < ch && ch < 9if isDigit {num num*10 int(ch-0)}if !isDigit && ch ! || i len(s)-1 {switch preS…

免杀笔记 ---> Session0--DLL注入

刚更新完上一篇&#xff0c;于是我们就马不停蹄的去跟新下一篇&#xff01;&#xff01; Session0注入 &#xff1a;&#xff1a; 各位看官如果觉得还不错的可以给博主点个赞&#x1f495;&#x1f495; 这次&#xff0c;我把这个脚本直接传到Github上了 喜欢的师傅点个Star噢…

VScode代码对齐快捷键

解决复制过来代码对齐格式问题。 左对齐&#xff1a;Ctrl[ 右对齐&#xff1a;Ctrl]