代理模式概述

news2024/10/6 20:25:32

1.代理模式概述

学习内容

1)概述

为什么要有 “代理” ?

  • 生活中就有很多例子,比如委托业务,黄牛(票贩子)等等
  • 代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,这才是“代理”存在的原因。
  • 例如要租房子,房产中介可以在我们住房前代理我们找房子。中介就是代理,而自己就是被代理了。

在代码设计中,代理模式作用主要就是让 “被代理对象” 的某个方法执行之或者执行之加入其他增强逻辑。

前增强 : 例如获取当前时间

被代理对象调用方法

后增强 : 例如获取当前时间

计算方法执行的时间

2)代理的前提条件 : 掌握 !

  • 抽象角色 :声明功能
  • 代理角色 :实现抽象功能 , 完成代理逻辑
  • 被代理角色 :实现抽象功能

意味着被代理角色和代理角色有着共同的父类型(既抽象角色) , 例如我要租房子, 我只能找房产中介, 不能找票贩子
在这里插入图片描述

  • 代理模式存在两种实现方式:

    • 静态代理
    • 动态代理

知识小结

  1. 请说出代码中代理模式的作用?

    代理角色对 被代理就角色某个方法执行的前或者后进行 功能增强
    
  2. 请说出代理模式中的三个角色?

    抽象角色
    代理角色
    被代理角色
    

==============================================================================================================

1.1 静态代理

学习目标

  • 能够写出静态代理模式代码

内容讲解

  • 静态代理是由程序员创建 或 工具生成代理类的源码,再编译代理类。

    在程序运行前就已经存在代理类的字节码文件,代理类和被代理类的关系在运行前就确定了。

    简单理解 : 在程序运行之前 , 代理类就存在了,这就是静态代理 ; 动态代理是程序运行时动态生成代理类

  • 静态代理实现的步骤 :

    • 存在一个抽象角色
    • 定义被代理角色
    • 定义代理,增强被代理角色的功能

案例实践 :

  • 以现实中经纪人代理明星

已知存在接口:

// 1.抽象角色
interface Star {
    // 真人秀方法
    double liveShow(double money);

    void sleep();
}

定义被代理类:

  • 定义王宝强类,实现Star方法
// - 定义被代理角色(宝强)
class BaoQiang implements Star {

    @Override
    public double liveShow(double money) {
        System.out.println("宝强参加了一个真人秀活动赚了" + money + "钱");
        return money;
    }

    @Override
    public void sleep() {
        System.out.println("宝强累了 , 睡觉...");
    }
}

定义代理类:

  • 定义宋喆经纪人类
// - 定义代理角色(宋喆),增强被代理角色的功能
class SongZhe implements Star {
    private BaoQiang baoQiang;

    public SongZhe(BaoQiang baoQiang) {
        this.baoQiang = baoQiang;
    }

    @Override
    public double liveShow(double money) {
        // 前增强
        System.out.println("宋喆帮宝强拉了一个真人秀的活动,获取佣金" + money * 0.8 + "元");
        // 被代理角色的功能
        double result = baoQiang.liveShow(money * 0.2);
        // 后增强
        System.out.println("宋喆帮宝强把赚的钱存了起来...");
        return result;
    }

    @Override
    public void sleep() {
        // 前增强
        System.out.println("宋喆帮宝强定了一家五星级大酒店");
        baoQiang.sleep();
        // 后增强
        System.out.println("宋喆帮宝强退房...");
    }
}

定义测试类进行测试

/*
    静态代理实现的步骤  :
        - 存在一个抽象角色
        - 定义被代理角色(宝强)
        - 定义代理角色(宋喆),增强被代理角色的功能
 */
public class StaticAgentDemo {
    public static void main(String[] args) {
        // 创建被代理角色 , 没有任何增强
        BaoQiang baoQiang = new BaoQiang();
        double result = baoQiang.liveShow(1000);
        System.out.println(result);
        baoQiang.sleep();

        System.out.println("===========================");

        // 创建代码角色对象 , 可以对被代理角色功能做前后增强
        SongZhe songZhe = new SongZhe(baoQiang);
        double result2 = songZhe.liveShow(1000);
        System.out.println(result2);

        songZhe.sleep();
    }
}

关系图 :

在这里插入图片描述
宋喆和宝强都有共同的父类型。他们的业务方法都是一样。

静态代理和装饰模式的对比 :

​ BufferedRead(FileRead)

​ 1 装饰设计模式是功能扩展功能,在原有的功能基础之上增加了新的功能

​ 2 而代理主要对功能的前后做了增强

知识小结

  • 请问什么叫做静态代理?

    代码执行前,已经确定了代理的代码逻辑。

2. 动态代理

学习目标

  • 能够知道什么是动态代理
  • 能够熟悉动态代理相关API
  • 能够熟悉动态代理代码执行流程

内容讲解

1)概述

在实际开发过程中往往我们自己不会去创建代理类而是通过JDK提供的Proxy类在程序运行时,运用反射机制动态创建而成

这就是我们所谓的动态代理

与静态代理之间的区别,在于不用自己写代理类

虽然我们不需要自己定义代理类创建代理对象

但是我们要定义对被代理对象直接访问方法的拦截,原因就是对拦截的方法做增强

动态代理技术在框架中使用居多,例如:很快要学到的数据库框架MyBatis框架等一些主流框架技术(Spring,SpringMVC)中都使用了动态代理技术。

2)API学习

Proxy类
  • java.lang.reflect.Proxy类提供了用于创建动态代理类和对象的静态方法

​ 它还是由这些方法创建的所有动态代理类的超类(代理类的父类是Proxy)。

public static Object newProxyInstance (
  ClassLoader loader, 
  Class<?>[] interfaces,  
  InvocationHandler h ) 获取代理对象的方法 

- 返回值:该方法返回就是动态生成的代理对象
- 参数列表说明:
  1. ClassLoader loader 	- 定义代理类的类加载器
  2. Class<?>[] interfaces 	- 代理类要实现的接口列表,要求与被代理类的接口一样。
  3. InvocationHandler h 	- 就是具体实现代理逻辑的接口
InvocationHandler接口

源码 :

interface InvocationHandler{
	public Object invoke(Object proxy, Method method, Object[] args);  //代理逻辑
}

java.lang.reflect.InvocationHandler是代理对象的实际处理代理逻辑的接口,具体代理实现逻辑在其 invoke 方法中。所有代理对象调用的方法,执行是都会经过invoke。因此如果要对某个方法进行代理增强,就可以在这个invoke方法中进行定义。

方法说明如下:

public Object invoke(Object proxy, Method method, Object[] args);
  
1. 返回值:方法被代理后执行的结果。
2. 参数列表:
   1. proxy  - 就是代理对象
   2. method - 代理对象调用的方法
   3. args   - 代理对象调用方法传入参数值的对象数组.

3)代码实践

将经纪人代理明星的案例使用动态代理实现

  1. 把父接口定义
  2. 定义被代理类:宝强
  3. 动态生成代理类
  4. 定义代理逻辑
package com.itheima.dynamicproxy_demo;

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

// 测试类
/*
    1 Proxy类 :
        public static Object newProxyInstance (
              ClassLoader loader,
              Class<?>[] interfaces,
              InvocationHandler h ) 获取代理对象的方法

            - 返回值:该方法返回就是动态生成的代理对象
            - 参数列表说明:
              1. ClassLoader loader 	- 定义代理类的类加载器
              2. Class<?>[] interfaces 	- 代理类要实现的接口列表,要求与被代理类的接口一样。
              3. InvocationHandler h 	- 就是具体实现代理逻辑的接口

    2 InvocationHandler接口
        public Object invoke(Object proxy, Method method, Object[] args);
        1. 返回值:方法被代理后执行的结果。
        2. 参数列表:
           1. proxy  - 就是代理对象
           2. method - 代理对象调用的方法
           3. args   - 代理对象调用方法传入参数值的对象数组.
 */
public class DynamicProxyDemo {
    public static void main(String[] args) {

        // Proxy.newProxyInstance(被代理角色的类加载器 , 被代理角色实现的所有接口 , 处理器);
        // 被代理角色的类加载器
        ClassLoader classLoader = BaoQiang.class.getClassLoader();
        // 被代理角色实现的所有接口
        Class<?>[] interfaces = BaoQiang.class.getInterfaces();
        // 创建被代理角色对象
        BaoQiang baoQiang = new BaoQiang();
        // 代理角色 , 动态生成
        Star songZhe = (Star) Proxy.newProxyInstance(classLoader, interfaces, new MyInvocationHandler(baoQiang));
        // 代理角色调用liveShow方法
        songZhe.liveShow(1000);
        songZhe.sleep();
    }
}

// 定义InvocationHandler接口的实现类
class MyInvocationHandler implements InvocationHandler {
    private BaoQiang baoQiang;

    public MyInvocationHandler(BaoQiang baoQiang) {
        this.baoQiang = baoQiang;
    }

    // invoke什么时候会执行????
    // 代理对象调用功能 , 就会触发invoke方法
    // 此方法对被代理角色的功能做增强

    // method : 代理对象调用功能就会触发invoke方法 , invoke方法中的method代表的就是调用的方法对象
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("liveShow")) {
            // 代理角色对象调用liveShow方法 , 此位置会拦截
            // 前增强
            System.out.println("宋喆帮宝强拉了一个真人秀的活动,获取佣金" + (double) args[0] * 0.8 + "元");
            Object result = method.invoke(baoQiang, (double) args[0] * 0.2);
            // 后增强
            System.out.println("宋喆帮宝强把赚的钱存了起来...");

            return result;
        } else if (method.getName().equals("sleep")) {
            // 代理角色对象调用sleep方法 , 此位置会拦截
            method.invoke(baoQiang);
        } else {
            // 除了liveShow和sleep方法 , 会执行else代码块中的内容
        }

        return null;
    }
}

//  1 抽象角色
interface Star {
    double liveShow(double money);

    void sleep();
}

// 2 定义被代理角色(宝强)
class BaoQiang implements Star {

    @Override
    public double liveShow(double money) {
        System.out.println("宝强参加了一个真人秀活动赚了" + money + "钱");
        return money;
    }

    @Override
    public void sleep() {
        System.out.println("宝强累了 , 睡觉...");
    }
}

动态代理调用流程:

在这里插入图片描述

小结

  1. 什么是动态代理?
    在代码执行前,没有代理类,代理类是在程序运行的时候动态生成.

    Proxy.newProxyInstance
    
  2. 动态代理有什么好处?
    动态代理可以为 “被代理对象” 的所有接口的所有方法做代理,动态代理可以在不改变方法源码的情况下,实现对方法功能的增强。

  3. 动态代理相关的API有哪些?

    Proxy
    	public static Object newProxyInstance(类加载器,接口列表,调用处理器)
    	类加载器 = 被代理对象.getClass().getClassLoader();
    	接口列表 = 被代理对象.getClass().getInterfaces();
    	调用处理器 = new InvocationHandler(){   实现  invoke 方法 };
    
    InvocationHandler
    	public Object invoke(代理对象,方法对象,方法的实参类别) 该方法执行时机是,代理对象调用方法时触发执行
    
  4. 动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。

  5. 缺点 :只能针对接口的实现类做代理对象,普通类是不能做代理对象的。

    后面框架学习的时候会接触到CGLib(Code Genneration Library ): 可以实现对类的代理

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

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

相关文章

地理数据的双重呈现:GIS与数据可视化

前一篇文章带大家了解了GIS与三维GIS的关系&#xff0c;本文就GIS话题带大家一起探讨一下GIS和数据可视化之间的关系。 GIS&#xff08;地理信息系统&#xff09;和数据可视化在地理信息科学领域扮演着重要的角色&#xff0c;它们之间密切相关且相互增强。GIS是一种用于采集、…

算法:深度优先遍历

文章目录 什么是深搜典型题目积累 本篇主要积累的是深度优先遍历算法 什么是深搜 深度优先搜索英文缩写为 DFS 即Depth First Search 其过程是对每一个可能的分支路径深入到不能再深入为止&#xff0c;而且每个节点只能访问一次 简单来说就是: 一路走到头&#xff0c;不撞墙…

ESD实时监测报警系统的主要功能

ESD&#xff08;Electrostatic Discharge&#xff09;实时监测报警系统是一种用于检测和预防静电放电的系统。静电放电是指在两个或多个物体之间由于电荷失衡而引起的突然放电现象&#xff0c;可能会对电子设备、化学品等敏感物体造成损害。 ESD实时监测报警系统的主要功能是通…

冠达管理:价格破发是什么意思啊?

价格破发是股票商场中一个比较常见的术语&#xff0c;也是常常让出资者感到困惑的现象之一。价格破发是指新股发行后&#xff0c;由于各种原因&#xff0c;股票价格低于发行价的现象。那么&#xff0c;价格破发的原因是什么呢&#xff1f;价格破发与出资者有哪些联系呢&#xf…

Stephen Wolfram:那么…ChatGPT 在做什么,为什么它有效呢?

So … What Is ChatGPT Doing, and Why Does It Work? 那么…ChatGPT在做什么&#xff0c;为什么它有效呢&#xff1f; The basic concept of ChatGPT is at some level rather simple. Start from a huge sample of human-created text from the web, books, etc. Then train…

ChatGPT写论文不靠谱?但可处理简单任务如编写摘要或生成代码

日前&#xff0c;一项题为《水果蔬菜消费和体力活动对成年人糖尿病风险的影响》的学术研究论文发布。乍一看&#xff0c;这似乎是在学术期刊上又发表的一个调查。然而这篇论文并不常见&#xff0c;因为它是在ChatGPT的帮助下只用了不到一个小时的时间完成的。[1] 本文包括摘要…

护眼灯值不值得买?什么护眼灯对眼睛好

想要选好护眼台灯首先我们要知道什么是护眼台灯&#xff0c;大的方向来看&#xff0c;护眼台灯就是可以保护视力的台灯&#xff0c;深入些讲就是具备让灯发出接近自然光特性的光线&#xff0c;同时光线不会伤害人眼而出现造成眼部不适甚至是视力降低的照明设备。 从细节上看就…

日常BUG——代码提交到了本地但是没有push,删除了本地分支如何恢复

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一、问题描述 代码在本地提交了&#xff0c;但是没有push到远程&#xff0c;然后删除了本地的分支。想要恢…

中国生产了5.07亿台,库存高达近4亿台?国产手机彻底卖不动了?

统计数据显示今年上半年中国的手机产量达到5.07亿台&#xff0c;国内市场手机出货量仅有1.24亿台&#xff0c;都出现了下滑&#xff0c;那么中国手机的产量比销量多出了3.83亿台&#xff0c;这些手机都成为了库存&#xff1f; 中国手机市场确实不如早年那么辉煌&#xff0c;201…

网盘与相册服务PDS

引言&#xff1a;作为一名开发者&#xff0c;我将通过对PDS&#xff08;Personal/Enterprise Drive System&#xff09;的体验使用&#xff0c;分享一下本人对以下方面的使用体验。 1. 开发个人/企业网盘 功能与应用 PDS作为一种网盘服务中间件产品&#xff0c;为开发者提供了…

常见程序搜索关键字转码

个别搜索类的网站因为用户恶意搜索出现误拦截情况&#xff0c;这类网站本身没有非法信息&#xff0c;只是因为把搜索关键字显示在网页中&#xff08;如下图&#xff09;&#xff0c;可以参考下面方法对输出的关键字进行转码 DEDECMS程序 本文针对Dedecms程序进行搜索转码&…

【腾讯云 TDSQL-C Serverless 产品体验】基于TDSQL-C 存储爬取的QQ音乐歌单数据

【腾讯云 TDSQL-C Serverless 产品体验】基于TDSQL-C 存储爬取的QQ音乐歌单数据 文章目录 【腾讯云 TDSQL-C Serverless 产品体验】基于TDSQL-C 存储爬取的QQ音乐歌单数据前言出现的背景一、TDSQL-C数据库是什么&#xff1f;二、TDSQL-C 的特点三、TDSQL-C的应用场景四、基于TD…

SpringBoot3入门第一章

现状 俗话说&#xff0c;买新不买旧&#xff0c;学技术也一样&#xff0c;学最新的技术&#xff0c;因为时代会给先行者最为优厚的回报 第一章 构建SpringBoot项目 这个因为太久没有用SpringBoot&#xff0c;导致好多东西都忘记了&#xff0c;就很烦 好在这里面东西并不多&…

【网络基础】网络通信

【网络基础】网络通信 文章目录 【网络基础】网络通信1、网络基础1.1 计算机网络1.2 网络模型TCP & UDP1&#xff09;IP地址2&#xff09;端口3&#xff09;TCP协议与UDP协议的比较 1.3 网络传输1.3.1 传输逻辑1.3.2 传输条件1.3.3 传输流程 1.4 地址管理 2、网络编程2.1 基…

React源码解析18(7)------ 实现事件机制(onClick事件)

摘要 在上一篇中&#xff0c;我们实现了useState的hook&#xff0c;但由于没有实现事件机制&#xff0c;所以我们只能将setState挂载在window上。 而这一篇主要就是来实现事件系统&#xff0c;从而实现通过点击事件进行setState。 而在React中&#xff0c;虽然我们是将事件绑…

ssm基于ssm的人才招聘网站源码和论文

ssm基于ssm的人才招聘网站源码和论文020 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 选题依据&#xff08;研究的背景、目的和意义等&#xff09; 在Internet飞速发展的今天&#xff0c;互联网成为人们快…

如何保证数据传输的安全?

要确保数据传输的安全&#xff0c;您可以采取以下措施&#xff1a; 使用加密协议&#xff1a;使用安全的传输协议&#xff0c;如HTTPS(HTTP over SSL/TLS)或其他安全协议&#xff0c;以保护数据在传输过程中的安全性。加密协议可以有效防止数据被窃听或篡改。 强化身份验证&…

【从零学习python 】28. Python中的局部变量和全局变量

文章目录 局部变量全局变量全局变量和局部变量名字相同问题修改全局变量查看所有的全局变量和局部变量函数返回值一、多个return?二、一个函数返回多个数据的方式 对返回的数据直接拆包进阶案例 局部变量 局部变量&#xff0c;就是在函数内部定义的变量其作用范围是这个函数内…

Java-java中的类,main函数和文件名的关系

java中的类&#xff0c;main函数和文件名的关系 类与文件名的关系 一个java文件中可以定义多个类&#xff0c;但是最多只有一个类被public修饰&#xff0c;并且这个类的类名与文件名必须相同&#xff0c;若这个文件中没有public的类&#xff0c;则文件名随便是一个类的名字即可…

JavaWeb-Filter过滤器

目录 Filter过滤器 1. Filter的生命周期 2.Filter的配置 3.拦截路径 4.拦截具体的使用 5.拦截方式配置&#xff08;资源被访问方式&#xff09; 6.FilterChain拦截链 Filter过滤器 filter是过滤器&#xff0c;相比于Servlet的发送请求&#xff0c;filter是用于拦截请求。…