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

代理模式:静态代理

目标

  • 了解静态代理模式实现

路径

  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;
    }
}

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

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

相关文章

深度学习:使用卷积神经网络CNN实现MNIST手写数字识别

引言 本项目基于pytorch构建了一个深度学习神经网络&#xff0c;网络包含卷积层、池化层、全连接层&#xff0c;通过此网络实现对MINST数据集手写数字的识别&#xff0c;通过本项目代码&#xff0c;从原理上理解手写数字识别的全过程&#xff0c;包括反向传播&#xff0c;梯度…

【第一阶段】kotlin语言的Nothing类型

fun main() {show(60) } //两种写法一样 private fun show(num:Int){when(num){//下面这句话不是注释提示&#xff0c;会终止程序-1->TODO("不符合")in 0..59->println("不及格")in 60..89->println("及格")in 90..100->println(&qu…

桥接模式(C++)

定义 将抽象部分(业务功能)与实现部分(平台实现)分离&#xff0c;使它们都可以独立地变化。 使用场景 由于某些类型的固有的实现逻辑&#xff0c;使得它们具有两个变化的维度&#xff0c;乃至多个纬度的变化。如何应对这种“多维度的变化”?如何利用面向对象技术来使得类型…

idea - 刷新 Git 分支数据 / 命令刷新 Git 分支数据

一、idea - 刷新 Git 分支数据 idea 找到 fetch 选项&#xff0c;重新获取分支数据 二、命令刷新 Git 分支数据 git fetch参考链接 1. 远程Gitlab新建的分支在IDEA里不显示

OSPF工作原理及其配置命令

目录 一、OSPF&#xff08;开放式最短路径优先协议&#xff09;&#xff1a; 作用&#xff1a;防环 弊端&#xff1a; 结构化部署: 更新方式&#xff1a; 二、OSPF的数据包 三、OSPF的状态机 Down Init 2way 条件&#xff1a; Exstart Exchange Loadi…

Pytorch量化之Post Train Static Quantization(训练后静态量化)

使用Pytorch训练出的模型权重为fp32&#xff0c;部署时&#xff0c;为了加快速度&#xff0c;一般会将模型量化至int8。与fp32相比&#xff0c;int8模型的大小为原来的1/4, 速度为2~4倍。 Pytorch支持三种量化方式&#xff1a; 动态量化&#xff08;Dynamic Quantization&…

Android 13 Hotseat定制化修改

一.背景 由于需求是需要自定义修改Hotseat,所以此篇文章是记录如何自定义修改hotseat的,应该可以覆盖大部分场景,修改点有修改hotseat布局方向,hotseat图标数量,hotseat图标大小,hotseat布局位置,hotseat图标禁止形成文件夹,hotseat图标禁止移动到Launcher中,下面开始…

Gpt微信小程序搭建的前后端流程 - 前端小程序部分-2.确定交互所需的后端API(二)

Gpt微信小程序搭建的前后端流程 - 前端小程序部分-2.确定交互所需的后端API(二) 参考微信小程序-小柠AI智能聊天&#xff0c;可自行先体验。 根据上一节的小程序静态页面设计&#xff0c;需要从后端获取数据的主要4个点&#xff1a; 登录流程&#xff1b;获取今日已提问次数&a…

[保研/考研机试] KY102 计算表达式 上海交通大学复试上机题 C++实现

描述 对于一个不存在括号的表达式进行计算 输入描述&#xff1a; 存在多组数据&#xff0c;每组数据一行&#xff0c;表达式不存在空格 输出描述&#xff1a; 输出结果 示例1 输入&#xff1a; 6/233*4输出&#xff1a; 18思路&#xff1a; ①设立运算符和运算数两个…

CSS的引入方式有哪些?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 内联样式&#xff08;Inline Styles&#xff09;⭐ 内部样式表&#xff08;Internal Stylesheet&#xff09;⭐ 外部样式表&#xff08;External Stylesheet&#xff09;⭐ 导入样式表&#xff08;Import Stylesheet&#xff09;⭐ 写在最…

HarmonyOS应用开发者基础认证考试题库

此博文为HarmonyOS应用开发者基础认证考试的最后的大考&#xff0c;要求100分取得90分方可获取证书、现将考试的题库进行分享&#xff0c;希望能帮到大家。但是需要注意的是&#xff0c;题库会不定时的进行题目删减&#xff0c;但是大概的内容是不会进行改变的。真心希望这篇博…

ArcGISPro随机森林自动化调参分类预测模型展示

更改ArcGISPro的python环境变量请参考文章 ArcGISPro中如何使用机器学习脚本_Z_W_H_的博客-CSDN博客 脚本文件如下 点击运行 结果展示 负类预测概率 正类预测概率 二值化概率 文件夹&#xff08;模型验证结果&#xff09; 数据集数据库 ROC曲线 由于个人数据量太少所以…

立即开始使用 3D 图像

一、说明 这个故事介绍了使用这种类型的数据来训练机器学习3D模型。特别是&#xff0c;我们讨论了Kaggle中可用的MNIST数据集的3D版本&#xff0c;以及如何使用Keras训练模型识别3D数字。 3D 数据无处不在。由于我们希望构建AI来与我们的物理世界进行交互&#xff0c;因此使用3…

Openlayers实战:多数据分散聚合

在飞机、轮船等地图显示的应用中,很多时候会用到数据聚合,Openlayers中提供了Cluster这个API ,他作为souce的一部分,设定distance值,如果2个点的间距小于 distance 所设置的数时,就会以聚合的方式显示。从而解决了数据淤积显示的状态,非常实用。 效果图 源代码 /* * @…

js 正则表达式

js 正则表达式 http://tool.oschina.net/regex https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions 11 22

1999-2021年全国各地级市专利申请与获得情况、绿色专利申请与获得情况面板数据

1999-2021年全国各地级市专利申请与获得情况、绿色专利申请与获得情况面板数据 1、时间&#xff1a;2000-2021年 2、来源&#xff1a;国家知识产权局 3、范围&#xff1a;地级市&#xff08;具体每年地级市数量参看下文图片&#xff09; 4、指标&#xff1a;申请专利数&…

数据结构----结构--线性结构--链式存储--链表

数据结构----结构–线性结构–链式存储–链表 1.链表的特点 空间可以不连续&#xff0c;长度不固定&#xff0c;相对于数组灵活自由 搜索&#xff1a; 时间复杂度O(n) 增删: 头增头删时间复杂度O(1) 其他时间复杂度为O(n) 扩展&#xff1a;单向循环链表的特性 从任意节…

基于kettle实现pg数据定时转存mongodb

mogodb 待创建 基于kettle实现pg数据定时转存mongodb_kettle 实时迁移 mongodb_呆呆的私房菜的博客-CSDN博客

【JUC】复习指南

JUC复习指南&#xff1a; JUC有哪些知识点&#xff1f; 什么是Juc Lock接口 线程间通信 集合的线程安全问题 多线程锁 Callable接口 JUC三大辅助类 CountDownLatch CyclicBarrier Semaphore 读写锁 ReetrantReadWriteLOck 阻塞队列 ThreadPool线程池 Fork/join Com…

CVE漏洞复现-CVE-2021-3493 Linux 提权内核漏洞

CVE-2021-3493 Linux 提权内核漏洞 漏洞描述 CVE-2021-3493 用户漏洞是 Linux 内核中没有文件系统中的 layfs 中的 Ubuntu over 特定问题&#xff0c;在 Ubuntu 中正确验证有关名称空间文件系统的应用程序。buntu 内核代码允许低权限用户在使用 unshare() 函数创建的用户命名…