栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

一篇文章理解JDK动态代理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

一篇文章理解JDK动态代理

文章目录
    • 前言
    • 1、何为代理
    • 2、静态代理
    • 3、动态代理

前言

java的设计模式中有一项设计模式叫做代理模式,所谓代理模式,就是通过代理方来操作目标对象,而不是自己直接调用。

代理又分为静态代理和动态代理,静态代理就是针对每个被代理对象写一个代理类,操作不够优雅;
动态代理,可以根据接口动态的生成代理类,这动态生成的类不需要自己书写,jdk帮你完成了。

该博客总结于动力节点视频教程,主要讲述了JDK动态代理(AOP)使用及实现原理分析。

1、何为代理

动态代理基于反射机制,在我们日常生活中有许多与代理有关的例子:代购、中介等。

比如说有一家美国大学,可以对全世界进行招生。这时就需要一个留学中介(代理) 替大学在全球各地招生。此时中介就是学校的代理,中介替学校完成招生功能。

代理特点:

  1. 中介和学校要做的事情是一致的:招生
  2. 中介是学校的代理,学校是目标
  3. 中介不能白白工作,需要收取代理费
  4. 中介(代理)不让你直接访问目标

为什么找中介(代理):

  1. 中介是专业的
  2. 学生没有能力直接访问学校(学校离得远不说,可能还不接受个人来访)

开发中也会遇到这样情况:我有一个A类,本来调用C类的方法完成某个功能,但是C不让A调用。
就在A和C之间创建一个代理类B,C类允许B类进行访问,此时情况就是:A——>B——>C

代理模式:为其他对象提供一种代理控制对这个对象的访问。当一个对象不适合直接引用另一个对象,这时代理对象就在客户类和目标对象之间起到中介作用
换句话说,使用代理对象,是为了不修改目标类的基础上,增强主业务逻辑

代理模式的作用:

  1. 功能增强:原有的功能上增加新功能
  2. 控制访问:代理类不让客户访问目标

实现代理的方式:

  1. 静态代理
  2. 动态代理
2、静态代理

静态代理:代理类自己手动实现,需要自己创建Java类表示代理类,同时代理的目标类时固定的

代码案例:买家购买U盘

卖U盘方法的接口:

public interface UsbSell {
    
    float sell(int amount);
}

代理类:

public class TaoBao implements UsbSell {
    
    private UsbSell factory = new UsbKingFactory();

    @Override
    public float sell(int amount) {
        //向厂家发送订单
        float price = factory.sell(amount); //厂家价格
        //商家 加价售卖
        //增强功能,代理类完成目标类方法调用后,增强了功能
        price = price + 25;
        //目标类方法调用后,做的其他功能都是增强的意思
        System.out.println("商家给您返回一个优惠券");
        return price;
    }
}

目标类:

public class UsbKingFactory implements UsbSell {
    
    @Override
    public float sell(int amount) {
        return 85.0f;
    }
}

测试类:

public class shopMain {
    public static void main(String[] args) {
        //创建代理对象
        TaoBao taoBao = new TaoBao();
        float price = taoBao.sell(1);
        System.out.println("通过商家购买U盘单价为:" + price); //单价为 110.0元
    }
}

通过上述代码,我们可以直到静态代理的缺点:

  1. 当目标类增加了,代理类可能需要成倍增加
  2. 当接口中功能增加、修改,会影响众多实现类、厂家类、代理类

动态代理可以解决以上缺点!

3、动态代理

动态代理优点:

  1. 在静态代理中目标类很多情况下,可以使用动态代理,解决静态代理的确定。
  2. 动态代理中目标类即便很多,代理类数量也可以很少。当我们修改接口中的方法,不会影响代理类

动态代理概念:
在程序的执行过程中,使用JDK反射机制,创建代理类对象,并动态的指定要代理的目标类。动态代理是一种创建Java对象的能力。

动态代理实现方式:

  1. JDK动态代理:使用Java反射包(java.lang.reflect)中的类和接口实现动态代理的功能。包中有三个类:InvocationHandler、Method、Proxy。该代理方式要求目标类必须有接口
  2. CGLIB动态代理(了解):cglib是第三方工具库,能够创建代理对象。cglib的原理是继承,通过创建子类继承目标类,在子类中重写父类中同名的方法,实现功能的修改。cglib对目标类的要求比较宽松,只要能继承就可以。在很多框架中使用过cglib,例如:Mybatis、Spring。cglib的代理效率高于JDK代理

JDK动态代理实现:
1):InvocationHandler接口:就一个方法invoke(),表示代理对象要执行的功能代码。

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

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

使用方式:

  1. 创建一个类实现接口InvocationHandler
  2. 重写invoke(),把原来静态代理中代理类要完成的功能写在invoke中

2):Method类:表示方法, 确切的说就是目标类中的方法,通过Method可以执行某个目标类中的方法,Method.invoke(目标对象,方法参数)

注意: 该invoke只是恰巧和InvocationHandler中的invoke方法同名而已,并不是同一个方法!

3):Proxy类:核心对象,创建代理对象。之前创建对象通过new,现在使用Proxy类的方法代替new创建对象。通过静态方法 newProxyInstance(),作用是创建代理对象

//返回值就是代理对象
public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)
方法参数:
1.ClassLoader loader: 类加载器,负责向内存中加载对象。使用反射获取对象的ClassLoader
A.getClass().getClassLoader(),目标对象的类加载器

2.Class interfaces: 接口,目标对象所实现的接口,也是反射获取的

3.InvocationHandler h: 我们自己写的,代理类要完成的功能

实现动态代理步骤:

  1. 创建接口,定义目标类要完成的功能
  2. 创建目标类实现接口
  3. 创建InvocationHandler接口实现类,在invoke方法中完成代理类的功能:调用目标方法,增强功能
  4. 使用Proxy静态方法创建代理对象,并把返回值转为接口类型

代码实现:

方法接口:

//方法接口
public interface UsbSell {
    float sell(int amount);
}

目标类:

//目标类
public class UsbKingFactory implements UsbSell {
    @Override
    public float sell(int amount) {
        //目标方法
        System.out.println("目标类中执行了sell目标方法");
        return 85.0f;
    }
}

InvocationHandler接口实现类:

//必须实现InvocationHandler接口,完成代理类要做的功能(调用目标方法,执行功能增强)
public class MySellHandler implements InvocationHandler {
    //目标对象
    private Object target = null;

    //动态代理;target目标对象是活动的,不是固定的,需要传入,然后创建代理
    public MySellHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //向厂家发送订单
        //float price = factory.sell(amount); //厂家价格
        Object res = method.invoke(target, args); //执行目标方法,等价于上一行注释
        //商家 加价售卖
        //增强功能,代理类完成目标类方法调用后,增强了功能
        //price = price + 25;
        if (res != null) {
            Float price = (Float) res;
            price += 25;
            res = price;
        }
        //目标类方法调用后,做的其他功能都是增强的意思
        System.out.println("商家给您返回一个优惠券");
        return res;
    }
}

测试类:

//测试类
public class MainShop {
    public static void main(String[] args) {
        //创建代理对象
        //1.创建目标对象
        UsbSell factory = new UsbKingFactory();
        //2.创建InvocationHandler对象
        InvocationHandler handler = new MySellHandler(factory);
        //3.创建代理对象
        UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
                factory.getClass().getInterfaces(), handler);
        //4.通过代理对象执行方法
        float price = proxy.sell(1);
        System.out.println("通过动态代理对象,调用方法:" + price);
    }
}

动态代理能做什么?

可以在不改变原来目标方法功能的前提下,可以在代理中增强自己的功能代码
例如:我们的项目中有一个功能是别人开发的,我可以使用。但是该功能不能满足我项目的需求
我需要自己增加一些代码,这时候就可以使用代理实现,而不用修改原来的代码

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/287048.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号