首页 > 其他分享 >动态代理

动态代理

时间:2022-11-01 23:25:13浏览次数:35  
标签:invoke 对象 Object 代理 目标 动态 方法

动态代理主要需要理解,其实现是基于反射机制。

代理模式

  • 当一个对象不能直接使用,可以在客户端和目标对象之间直接创建一个中介,这个中介就是代理。

动态代理作用

1、控制访问

  • 在代理中,控制是否可以调用目标对象的方法

2、功能增强

  • 可以在完成目标对象的调用时,附加一些额外的功能,这些额外的功能就叫做功能增强。

代理的实现方式

1、 静态代理

  • 代理类是手工实现的 Java 文件,同时代理的对象是固定的。

优点:容易理解,使用方便

缺点:在目标类比较多的情况下,会产生大量的代理类;当接口改变时,影响的目标类成倍增加

2、动态代理

  • 使用反射机制,在程序执行中,动态创建代理类对象。

特点:不用创建类文件,代理的目标类是活动的,可设置的。

优点:不用创建代理类;可以给不用的目标随时创建代理。

动态代理实现方式

1、JDK 动态代理(理解)

  • 使用 java 反射包中的类和接口实现动态代理的功能
  • 反射包 java.lang.reflect ,里面有三个类 : InvocationHandler ,Method,Proxy.
1)InvocationHandler 接口(调用处理器):就一个方法invoke()
	invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在 invoke() 方法中。
    代理类完成的功能:
    1. 调用目标方法,执行目标方法的功能
	2. 功能增强,在目标方法调用时,增加功能。

方法原型:
public Object invoke(Object proxy, Method method, Object[] args)

参数: 
Object proxy:jdk创建的代理对象,无需赋值。
Method method:目标类中的方法,jdk提供method对象的
Object[] args:目标类中方法的参数, jdk提供的。

InvocationHandler 接口:表示你的代理要干什么

怎么用: 
1.创建类实现接口InvocationHandler
2.重写invoke()方法, 把原来静态代理中代理类要完成的功能,写在这。


2)Method类:表示方法的, 确切的说就是目标类中的方法。
作用:通过Method可以执行某个目标类的方法,Method.invoke();
method.invoke(目标对象,方法的参数)
Object ret = method.invoke(service2, "李四");

说明: 
method.invoke()就是用来执行目标方法的,等同于静态代理中的
//向厂家发送订单,告诉厂家,我买了u盘,厂家发货
float price = factory.sell(amount); //厂家的价格。

3)Proxy类:核心的对象,创建代理对象。之前创建对象都是 new 类的构造方法()
现在我们是使用Proxy类的方法,代替new的使用。 

方法: 静态方法 newProxyInstance() 
作用是: 创建代理对象, 等同于静态代理中的TaoBao taoBao = new TaoBao();

方法原型:
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
参数:
1. ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader
类a , a.getCalss().getClassLoader(),  目标对象的类加载器
2. Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
3. InvocationHandler h : 我们自己写的,代理类要完成的功能。 

返回值:就是代理对象

​ jdk 动态代理,必须有接口,目标类必须实现接口,没有接口时,需要使用 cglib 动态代理。

实现步骤:

  1. 创建接口,定义目标类要完成的功能

    public interface UsbSell {
        float sell(int amount);
    }
    
  2. 创建目标类,实现接口

    public class UsbKingFactory implements UsbSell {
        @Override
        public float sell(int amount) {
            System.out.println("目标方法执行:出厂价89");
            return 89f;
        }
    }
    
  3. 创建 InvocationHandler 接口的实现类,重写 invoke 方法,在其 invoke 方法中完成代理类的功能

    1. 调用目标方法
    2. 增强功能
    public class MySellHandler implements InvocationHandler {
        // 目标对象
        private Object target;
        // 通过无参构造赋值
        public MySellHandler(Object target) {
            this.target = target;
        }
        @Override
        // 在此方法中调用目标方法,并附加额外功能
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 通过动态代理,调用目标对象的目标方法
            Object res = method.invoke(target, args);
            // 在此添加额外功能
            if (res != null) {
                Float price = (Float) res;
                price += 10;
                res = price;
                System.out.println("功能增强:中介加价后价格" + price);
            }
            return res;
        }
    }
    
  4. 使用 Proxy 类的静态方法,创建代理对象,并把返回值转为接口类型

    public class SellMain {
        public static void main(String[] args) {
            // 创建目标对象
            UsbSell usbKingFactory = new UsbKingFactory();
            // 创建完成了目标方法调用和功能增强的自定义InvocationHandler接口实现类
            MySellHandler handler = new MySellHandler(usbKingFactory);
            // 创建动态代理对象
            UsbSell proxy = (UsbSell) Proxy.newProxyInstance(
                			usbKingFactory.getClass().getClassLoader(),
                          	usbKingFactory.getClass().getInterfaces(),
    			            handler);
            // 通过动态代理对象,调用指定方法
            proxy.sell(1);
        }
    }
    

2、cglib 动态代理(了解)

  • cglib 是第三方的工具库,创建代理对象
  • 原理是继承,cglib 通过继承目标类,创建它的子类,在子类中重写父类中同名的方法,实现功能的修改
  • 因为 cglib 是继承,重写方法,所以要求目标类不能是 final 的,方法也不能是 final 的
  • cglib 的要求目标类比较宽松,只要能继承即可
  • cglib 在很多的框架中使用,如 mybatis 和 spring

标签:invoke,对象,Object,代理,目标,动态,方法
From: https://www.cnblogs.com/luisblog/p/16849532.html

相关文章

  • 1480. 一维数组的动态和
    给你一个数组nums。数组「动态和」的计算公式为:runningSum[i]=sum(nums[0]…nums[i])。请返回nums的动态和。 示例1:输入:nums=[1,2,3,4]输出:[1,3,6,10]解释:......
  • 嵌入式-C语言基础:malloc动态开辟内存空间
    #include<stdio.h>#include<stdlib.h>intmain(){//char*p;//定义一个野指针:没有让它指向一个变量的地址//*p='c';//直接对野指针进行操作,会报错ch......
  • 如何解决何避免多个C/C++动态库函数同名冲突
    前言现在的开发节奏越来越快,有大量现成的库来方便我们的开发者来使用,避免重复造轮子,而且有很多有生命力的开源社区。当然在使用过程中,你可能为这样的场景而头痛:你的项目中用......
  • Jenkins Pipeline 流水线 - 添加节点 使用代理
    Jenkins安装在Windows上Docker在Linux上流程将Docker在Jenkins节点中维护Pipeline中指定某些阶段使用哪个节点添加节点CheckingJavaversionint......
  • 动态规划-零钱兑换
    零钱兑换也是动态规划的典型问题,一般是给你几种零钱,数量不限,给一个amount,问共有多少种兑零钱的方法。我们看一个案例案例1:给你一个整数数组coins,表示不同面额的硬币;以......
  • Eolink 10月企业与产品动态速览
    本月,值得关注的产品好消息莫过于Eolink私有云10.5.4版本发布,以及开源项目Eoapiv1.8.0版本发布。Eolink深耕于API领域并持续探索前行,作为标准撰写单位之一参与......
  • 关于代理的设置
    环境变量设置代理全局设置代理就使用环境变量配置(这里只针对Linux或者Mac)vim/etc/profile--------------------------------------------http_proxy=IP:PORThttps_pr......
  • 动态规划学习入门(小白零基础)
    动态规划学习入门(小白零基础)基础概念如果某一问题可拆解成若干重叠子问题,即可用动态规划解决。重叠子问题:比如斐波那契数列F(n)可分解成F(n-1)+F(n-2),而F(n-1)又可......
  • 学习笔记——动态 dp
    前言好消息,CSP-St4出DDP,并且有的人场上为了调T3的假算没写。。。概述其实是个挺简单的东西,就是如果一道题可以通过dp轻松解决,但是题目加上了每次询问修改一些信......
  • 动态规划-回文串
    回文串是从左到右和从右到左读起来一样的字符串,变种还有回文子序列,区别就是字符可以不连续。求回文串个数、最长回文串、最长回文序列也是典型的二维动态规划问题。我们......