【Java-16】动态代理的使用方法及原理实现

news2024/9/24 11:29:07

代理模式:静态代理

目标

  • 了解静态代理模式实现

路径

  1. 静态代理概述
  2. 静态代理案例

静态代理概述

静态代理:

  • 是由程序员创建或工具生成代理类的源码,再编译成为字节码 (字节码文件在没有运行java之前就存在了)

  • 在编译时就已经将接口、代理类、被代理类的关系确定下来了

  • 在程序运行之前就已经存在代理类的.class文件

不论是哪一种代理模式,都需要3个角色:

  • 抽象角色(父接口:定义方法) //程序员自己定义(程序运行之前就存在了)
  • 被代理角色(被代理类) //程序员自己定义(程序运行之前就存在了)
  • 代理角色(代理类) //程序员自己定义(程序运行之前就存在了)

静态代理的实现方式:

  • 被代理类和代理类,都实现父接口
  • 被代理类,会作为代理类中的成员存在

静态代理案例

案例:经纪人代理明星

已知存在接口:

//1.抽象角色
interface Star {
    double liveShow(double money);
    void sleep();
}

定义被代理类: 王宝强类,实现Star方法

//2.被代理:宝强
class BaoQiang implements Star {
    @Override
    public double liveShow(double money) {
        System.out.println("宝强赚了:" + money + "元");
        return money;
    }

    @Override
    public void sleep() {
        System.out.println("宝强在睡觉~~");
    }
}

定义代理类: 经纪人宋喆类

//3.代理:宋喆
class SongZhe implements Star {
    //被代理对象
    private BaoQiang baoQiang;

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

    //代理:就是被代理方法执行前,后做增强
    @Override
    public double liveShow(double money) {
        //前增强
        System.out.println("前置增强:宋喆接了一个跑男节目收到" + money + ",抽取佣金" + money * 0.8);

        double m = baoQiang.liveShow(money * 0.2); //被代理方法执行
        
        //后增强
        System.out.println("后置增强:宋喆帮宝强存了" + m + "元");
        return m;
    }

    @Override
    public void sleep() {
        System.out.println("宋喆帮宝强,找了一个6星级酒店~~");

        baoQiang.sleep();

        System.out.println("宋喆帮宝强退房");
    }
}

定义测试类:

public class Demo01 {
    public static void main(String[] args) {
        //被代理
        BaoQiang baoQiang = new BaoQiang();

        //代理
        SongZhe songZhe = new SongZhe(baoQiang);

        double v = songZhe.liveShow(100);
        System.out.println("v = " + v);

        System.out.println();
        System.out.println();

        songZhe.sleep();
    }
}

关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gsx8LON9-1691573608539)(imgs\image-20200908092851064-1611662375106.png)]

宋喆和王宝强都有共同的父类型,具有相同的业务方法

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

原则上的区别,代理为了控制对某个函数前后的操作,而装饰着模式是为了添加某一操作(其实目标没差太远)

小结

静态代理:

  • 需要有三个角色:抽象角色(父接口)、被代理角色(被代理类)、代理角色(代理类)
    • 被代理类和代理类,都是实现父接口
  • 在程序执行之前,就要确定了三个角色关系,生成.class文件(在程序运行之前就已经生成了)
    • 随着程序的执行,.class文件都会被加载到jvm中

17_代理模式:动态代理概述

目标

  • 了解什么是动态代理

路径

  1. 动态代理概述

动态代理

在上面静态代理的例子中,代理类(SongZhe)是自己定义好的,在程序运行之前就已经编译完成

然而动态代理中,代理类是在程序运行时利用反射机制动态创建的,这种代理方式被成为动态代理

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

  • 大白话:静态代理需要自己写代理类、动态代理不用自己写代理类

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

虽然我们不需要自己定义代理类创建代理对象,但是我们要定义对被代理对象访问方法的拦截逻辑

  • 代理类的作用,就是让被代理对象的某个方法执行之前或者执行之后加入其他增强逻辑(要在被代理对象的方法执行前进行拦截)

小结

动态代理:

  • 不用程序员自己书写代理类,使用JDK提供的Proxy类实现代理
  • 动态代理是在程序执行过程中,利用反射技术,动态的创建代理类对象

18_代理模式:动态代理流程图

目标

  • 理解动态代理模式执行流程

路径

  1. 图解分析动态代理执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5DYFXFC-1691573608540)(imgs\image-20210126214457929.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BqpdTFRg-1691573608540)(imgs\image-20210127121202995.png)]

19_代理模式:动态代理API

目标

  • 熟悉动态代理相关API

路径

  1. 动态代理API介绍

动态代理API

在java中实现动态代理,关键要使用到一个Proxy类和一个InvocationHandler接口

Proxy类

java.lang.reflect.Proxy:是 Java 动态代理机制的主类(父类),它提供了用于创建动态代理类和实例的静态方法

public static Object newProxyInstance(
                                      ClassLoader loader, 
                                      Class<?>[] interfaces, 
                                      InvocationHandler handle 
                                     ) 
**解释说明:    
- 返回值:     该方法返回就是动态生成的代理对象
- 参数列表说明:
  ClassLoader loader         :定义代理类的类加载器
  Class<?>[] interfaces      :代理类要实现的接口列表,要求与被代理类的接口一样
  InvocationHandler handle   :就是具体实现代理逻辑的接口 
    
    
//参数的应用:
ClassLoader loader     //对象.getClass().getClassLoader()  
           //目标对象通过getClass方法获取类的所有信息后,调用getClassLoader()方法来获取类加载器
           /*获取类加载器后,可以通过这个类型的加载器,在程序运行时,将生成的代理类加载到JVM即Java              虚拟机中,以便运行时需要*/ 
    
Class<?>[] interfaces  //对象.getClass().getInterfaces() 
           //获取被代理类的所有接口信息,以便于生成的代理类可以具有代理类接口中的所有方法
    
    
InvocationHandler 
          //用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类方法的处理以及访问  

InvocationHandler接口

java.lang.reflect.InvocationHandler是代理对象的实际处理代理逻辑的接口,具体代理逻辑在其 invoke 方法中实现

public Object invoke(Object proxy, Method method, Object[] args)
**解释说明:
- 返回值:方法被代理后执行的结果
- 参数列表说明:
  Object proxy   :  就是代理对象(通常不使用)
  Method method  :  代理对象调用的方法
  Object[] args  :  被代理方法中的参数 (因为参数个数不定,所以用一个对象数组来表示)
                     如果方法不使用参数,则为 null
    
//所有代理对象调用的方法,执行是都会经过invoke
//因此如果要对某个方法进行代理增强,就可以在这个invoke方法中进行定义    

20_代理模式:动态代理实现

目标

  • 掌握动态代理模式代码书写逻辑

路径

  1. 案例:使用动态代理实现明星经纪人

案例

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

前置动作:

  1. 定义父接口
  2. 定义被代理类:王宝强
//父接口(抽象角色)
interface Star {
    double liveShow(double money);

    void sleep();
}

//被代理类:王宝强
class BaoQiang implements Star {
    @Override
    public double liveShow(double money) {
        System.out.println("宝强表演节目,赚了" + money + "元");
        return money;
    }

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

动态代理类生成:

public class Demo01 {
    public static void main(String[] args) {
        //创建被代理对象
        BaoQiang baoQiang = new BaoQiang();

        //创建代理对象
        //获取类加载器
        ClassLoader loader = baoQiang.getClass().getClassLoader();
        //获取被代理类的接口
        Class[] interfaces = baoQiang.getClass().getInterfaces();//Star
        //定义调用处理器(具体实现业务代理)
        InvocationHandler handler = new MyInvocationHandler(baoQiang);

        Object proxyObj = Proxy.newProxyInstance(loader, interfaces, handler);
        
        //proxyObj :即是Proxy的子类,也是Star的实现类
        Star starProxy = (Star) proxyObj;//多态

        double money = starProxy.liveShow(100);//这里一调用就会传入到invoke,invoke方法运行结束又会传回来
        
        System.out.println("money = " + money);

        starProxy.sleep();
    }
}

定义代理逻辑:

//具体实现代理逻辑
class MyInvocationHandler implements InvocationHandler {
    private BaoQiang baoQiang;

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

    //代理对象调用的方法,都会经过这里
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //写代理逻辑
        String methodName = method.getName();
        System.out.println("调用的方法是:" + methodName + ",入参:" + Arrays.toString(args));

        //代理liveShow
        if (methodName.equals("liveShow")) {
            //前增强
            double m = (double) args[0];
            System.out.println("宋喆抽取佣金" + m * 0.8);
            
            Object result = method.invoke(baoQiang, m * 0.2);
            
            //后增强
            System.out.println("宋喆帮宝强存了" + result + "元到银行");
           
            return result;
        }

        //不写代理逻辑
        Object result = method.invoke(baoQiang, args);
        System.out.println("被代理调用结果" + result);
        return result;
    }
}

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

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

相关文章

Linux——常用命令(2)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 前期回顾 【新星计划Linux】——常用命令&#xff08;1&#xff09; 目录 一.其它常用命…

vue或uniapp使用pdf.js预览

一、先下载稳定版的pdf.js&#xff0c;可以去官网下载 官网下载地址 或 pdf.js包下载(已配置好&#xff0c;无需修改) 二、下载好的pdf.js文件放在public下静态文件里&#xff0c; uniapp是放在 static下静态文件里 三、使用方式 1. vue项目 注意路径 :src"static/pd…

在矩池云使用ChatGLM-6B ChatGLM2-6B

ChatGLM-6B 和 ChatGLM2-6B都是基于 General Language Model (GLM) 架构的对话语言模型&#xff0c;是清华大学 KEG 实验室和智谱 AI 公司于 2023 年共同发布的语言模型。模型有 62 亿参数&#xff0c;一经发布便受到了开源社区的欢迎&#xff0c;在中文语义理解和对话生成上有…

语音信号的A律压缩和u律压缩matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 A律压缩算法 4.2 μ律压缩算法 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 clc; clear; close all; warning off; addpath(genpath(…

DanceFight VoxEdit 大赛

准备好让自己的创造力更上一层楼了吗&#xff1f;别再犹豫了&#xff0c;The Sandbox 将为你们带来一场激动人心的挑战&#xff0c;让你们的 VoxEdit 技能和舞蹈动作激情四射&#xff01;准备好参加终极数字盛会——DanceFight VoxEdit 大赛&#xff01;&#x1f57a;&#x1…

物理层扩展以太网

扩展站点与集线器之间的距离&#xff1a;   在10BASE-T星型以太网中&#xff0c;可使用光纤和一对光纤调制解调器来扩展站点与集线器之间的距离。   为站点和集线器各增加一个用于电信号和光信息号转换的光纤调制解调器&#xff0c;以及他们之间的通信光纤。 扩展共享式以太…

ICS PA0

目录 环境配置工具的使用及相关资源Compling and Running NEMU配置系统make menuconfig项目构建make运行与调试 Submit 环境配置 Ubuntu安装中的分区不太明白安装了中文输入法和必要的工具链虚拟机与主机互联 工具的使用及相关资源 vim&#xff08;vimtutor是vim的一个内置教…

Nginx跳转模块——location与rewrite

一、location 1、location作用 用于匹配uri&#xff08;文件、图片、视频&#xff09; uri&#xff1a;统一资源标识符。是一种字符串标识&#xff0c;用于标识抽象的或物理资源文件、图片、视频 2、locatin分类 1、精准匹配&#xff1a;location / {...} 2、一般匹配&a…

【80天学习完《深入理解计算机系统》】第三天 2.3 整数运算【正负溢出】【运算的溢出】【类型转换的二进制扩展】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

ATF(TF-A)安全通告 TFV-6 (CVE-2017-5753, CVE-2017-5715, CVE-2017-5754)

ATF(TF-A)安全通告汇总 目录 一、ATF(TF-A)安全通告 TFV-6 (CVE-2017-5753, CVE-2017-5715, CVE-2017-5754) 二、Variant 1 (CVE-2017-5753) 三、Variant 2 (CVE-2017-5715) 四、Variant 3 (CVE-2017-5754) 一、ATF(TF-A)安全通告 TFV-6 (CVE-2017-5753, CVE-2017-5715, C…

向量数据库介绍

1.什么是向量数据 向量数据库是一种专门用于存储和检索向量数据的数据库。它不同于传统的关系型数据库&#xff0c;而是基于向量相似度匹配的方式来实现高效的数据查询和分析。 向量数据库的应用场景非常广泛&#xff0c;包括但不限于以下几个方面&#xff1a; 图片、音频和视频…

微服务02-docker

1、Docker架构 1.1 镜像和容器 Docker中有几个重要的概念&#xff1a; 镜像&#xff08;Image&#xff09;&#xff1a;Docker将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起&#xff0c;称为镜像。Docker镜像是用于创建 Docker 容器的模板 。就像面向对象编…

js代码执行顺序(同步与异步)

1.同步与异步 异步任务又分为宏任务和微任务 2.执行规则 同步代码遇到,直接执行Promise中.then前的代码直接执行,.then后的代码丢入微任务队列中遇到定时器直接将里面的代码丢入宏任务队列中同步代码执行完&#xff0c;去看微任务,有则执行&#xff1b;再去看宏任务&#xf…

文件的权限

1、修改文件的所属者和所属组 2、修改文件某一类人&#xff08;所属者、所属组、其他人&#xff09;的权限 一、用户对于普通文件的权限 二、用户对于目录文件的权限 三、访问控制列表ACL 四、特殊权限&#xff08;了解&#xff09; wuneng创建了几个文件&#xff0c;xiaoming对…

【C语言】预处理详解

本文目录 1 预定义符号 2 #define 2.1 #define 定义标识符 2.2 #define 定义宏 2.3 #define 替换规则 2.4 #和## 2.5 带副作用的宏参数 2.6 宏和函数对比 2.7 命名约定 3 #undef 4 命令行定义 5 条件编译 6 文件包含 6.1 头文件被包含的方式 6.2 嵌套文件包含 1 预定义符号 __…

2023亚马逊秋季大促定档!卖家要做好准备!

亚马逊Prime秋季促销&#xff0c;又称亚马逊Prime会员早享日&#xff08;Prime Early AccessSale&#xff09;&#xff0c;是亚马逊在2022年才正式推出的一个面向Prime会员的促销活动&#xff0c;与每年7月举办的Prime Day大促是同等级活动&#xff0c;去年秋季大促也是在10月举…

C - The Battle of Chibi

题意&#xff1a;就是问你数组中长度为m的上升子序列(没说连续&#xff09;有多少个。 1&#xff1a;可以想到状态表示dp[ i ][ j ] 代表以 a[i] 为结尾的且长度为 j 的严格单增子序列的数目&#xff0c; 那么状态计算就为 , 那我们如果不优化直接写&#xff0c;一层n&am…

数据结构刷题训练——链表篇(一)

目录 前言 题目一&#xff1a;链表的中间节点 思路 分析 题解 题目二&#xff1a;链表中倒数第k个结点 思路 分析 题解 题目三&#xff1a;合并两个有序链表 思路 分析 题解 方法二 题解 题目四&#xff1a;链表的回文结构 思路 分析 题解 总结 前言 今天我将开…

家政小程序开发制作

家政小程序是一种基于移动互联网的工具&#xff0c;旨在为用户提供方便快捷的家政服务。下面是家政小程序的功能介绍&#xff1a; 1. 家政服务展示&#xff1a;家政小程序可以展示各类家政服务的详细信息&#xff0c;包括清洁、保姆、月嫂、保洁等多种服务项目&#xff0c;以及…

【vue3】基础知识点-pinia

学习vue3&#xff0c;都会从基础知识点学起。了解setup函数&#xff0c;ref&#xff0c;recative&#xff0c;watch、computed、pinia等如何使用 今天说vue3组合式api&#xff0c;pinia 戳这里&#xff0c;跳转pinia中文文档 官网的基础示例中提供了三种写法 1、选择式api&a…