JDK动态代理

动态代理(理解)

这笔记能让你把动态代理掌握到什么程度呢?

1.什么是动态代理?

2.动态代理能做什么?

3.mybatis spring 框架中提到动态代理 你不会懵逼;

第一章:代理的介绍

1.什么是代理

代理 无处不在;

中介,商家,代购等等;

比如有一个美国大学,面向全世界招生, 留学中介(代理);

留学中介(代理):帮助这家美国学校招生,中介就是学校的代理,中介代替学校招生;

这个 中介就是代理

代理的特点

1.中介和代理他们要做的事情是一致的:招生;

2.中介是学校的代理,学校是目标

3.家长------中介(代理)------学校(目标)

4.中介是代理,不能白干活,需要收取费用

5.代理不让你访问到 目标;

为什么要找中介呢?

1.中介专业 方便;

2.家长不方便直接去找学校,家长不能直接访问学校,或者学校不接受个人来访 只接受代理访问

2.开发中的情况

有一个a类, 需要调用c类的方法 ,但是c不让a调用;

a-----不能调用c类的方法

在 a和 c中间创建一个 代理 b ,c让b访问;

a—访问 b(代理)-----访问c(目标);

实际案例:登陆 注册 验证码,验证码是手机短信

中国移动 中国联通能发短信

中国移动 中国联通 有子公司或者关联公司,他们面向社会提供短信发送功能

张三项目发短信------------------->(代理)子公司或者关联公司------------------->(目标)中国移动 中国联通

3.代理好处

使用代理模式的作用/好处:

  • 功能增强:在目标功能的基础上,增加额外的功能,新增加的功能叫做功能增强
  • 控制访问:代理类不让你访问目标,
  • 解耦:将客户端 与 目标对象 分离,在一定程度上降低了系统的耦合度
  • 保护: 不让客户端直接访问 目标对象,代理对目标对象起到一定的保护作用

缺点:也是增加了程序的复杂度

第二章:静态代理

静态代理

  • 代理类是自己手工实现的,自己创建一个类,表示为代理类
  • 同时你的目标对象也是明确的
  • 优点:
  • 实现简单 ,容易理解
  • 缺点:
    • 当你的项目中,有很多的目标类和代理类时候 有一下缺点
    • 当目标类增加了,代理类有可能成倍的增加,代理类数量过多
    • 接口功能的增加或者修改,会影响众多的实现类,目标类,代理类都需要修改

模拟一个用户购买U盘的案例

关系分析:

用户:是客户端类;

商家:是代理类,代理某个品牌的U盘

厂家:是目标;

三者关系:用户购买U盘----- (代理)商家------>(目标)厂家

商家和厂家 都是卖U盘的 ,他们完成的功能是一致的,都是卖U盘的;

实现步骤:

1.创建一个接口,定义卖U盘的方法,表示你的厂家和商家做的事情;

(依赖倒置原则:尽量面向接口编程[高层模块不应该以来底层模块,都应该依赖于抽象; 抽象不应该依赖于细节,细节应该依赖于抽象])

2.创建厂家类,实现步骤1

3.创建商家类 实现步骤1,并且聚合厂家类(合成复用原则:尽量先使用组合或者聚合等关联关系;)

4.创建客户端类,调用商家的卖U盘的方法;

package chapter03;
//目标类
public class UsbFactory implements UsbSell{

    @Override
    public float sellUsb(int num) {
        //厂家 1000个卖95 1W个 85  10W个75
        //厂家的出厂价
        return  75l;
    }
}


package chapter03;
//代理类
public class TaoBao implements UsbSell{
    //组合关系
    private UsbFactory usbFactory =new UsbFactory();

    @Override
    public float sellUsb(int num) {
        float v = usbFactory.sellUsb(num);
        //增强功能: 增加了价格;
        //在你的目标类方法调用之后 ,你做的其他功能 都是增强功能;
        float c = (v+25)*num;

        //增加后的价格
        return c;
    }
}

package chapter03;

public class User {
    public static void main(String[] args) {
        TaoBao taoBao = new TaoBao();
        float v = taoBao.sellUsb(2);
        System.out.println("向买了两个U盘花费"+v);

    }
}

第三章 动态代理

1.动态代理的介绍

动态代理

我们可以使用动态代理去避免静态代理的缺点;

1.代理类数量可以很少;

2.当修改了接口的方法时,不会影响代理类

动态代理:在程序的执行的过程中,使用jdk的反射机制,创建代理类对象 ,并且动态的指定要代理的目标类

再详细的解释:

  1. 动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的,java源文件。
  2. 动态代理其实就是jdk运行期间,动态创建class字节码并加载到JVM。
  3. 动态代理的实现方式常用的有两种:使用JDK代理,与通过CGLlB动态代理。

动态代理的实现:

  • jdk动态代理(理解):使用java反射包中的类和接口实现动态代理的功能,反射包java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy
  • cglib动态代理(了解): cglib是第三方的工具库,创建代理对象
    • cglib的原理是继承,cglib通过继承目标类,创建它的子类,在子类中
      重写父类中同名的方法,实现功能的修改。
    • 因为cglib是继承,重写方法,所以要求目标类不能是fina1的,方法也不能是final的。cglib的要求目标类比较宽松,只要能继承就可以了。cglib在很多的框架中使用,
      比如mybatis,spring框架中都有使用

2.回顾反射

Method类的结构图

  • Class Method
    • java.lang.Object
      • java.lang.reflect.AccessibleObject
        • java.lang.reflect.Executable
          • java.lang.reflect.Method

Method对象调用invoke(Object obj, Object… args);

第一个参数 :表示对象,表示执行这个对象的方法;

第二个参数:表示执行时,参数值;

返回值Object ,方法执行后的返回值;

3.JDK动态代理:

使用到的 三个类 :

InvocationHandler接口(调用处理器):就一个 方法 invoke();

invoke();表示代理对象要执行的功能代码。代理类要完成的功能就卸载 invoke();中

  1. 调用目标对象的方法并执行 2.功能增强,在目标方法调用时增加功能

invoke()方法原型:

// Object proxy :创建的代理对象 ,无需赋值
//Method method 目标类中的方法  无需赋值
//Object[]args  目标类中方法的参数  无需赋值
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

**Method 类:表示方法的,确切的说就是目标类中的方法 **

作用:通过Method可以执行某个目标类的方法,Method.invoke(目标对象,方法参数);

Proxy类:核心对象,创建代理对象。

静态方法: newProxyInstance(); 该方法是用来创建代理对象;

newProxyInstance()方法原型

//ClassLoader loader 类加载器负责向内存中加载对象;
// Class<?>[] interfaces 目标对象实现的接口类
// InvocationHandler h 我们自己写的代理类要完成的功能
//返回值 Object 就是代理对象
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException

代码实现:

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

2.创建目标类实现接口

3.创建 InvocationHandler接口的实现类,在invoke方法中完成代理类的功能

4.使用Proxy的静态方法,创建代理对象。并把返回值类型转为接口类型

package cha04_dynamic_proxy.service;
//接口
public interface UsbSell {

    float usbSell(int num);
}
-------------------------------------------------------
package cha04_dynamic_proxy.factory;
import cha04_dynamic_proxy.service.UsbSell;
//目标对象
public class UsbFactory implements UsbSell {


    @Override
    public float usbSell(int num) {

        return 75*num;
    }
}
-----------------------------------------------------------
package cha04_dynamic_proxy.handler;
import cha04_dynamic_proxy.service.UsbSell;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MySellHandller implements InvocationHandler {
    private UsbSell target=null;
    //这里使用的聚合关系,  传进来哪个目标对象 就给谁创建代理
    public MySellHandller(UsbSell target) {
        this.target=target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理类要做的事情 :
        //1. 调用目标对象方法并执行;
        Object invoke = method.invoke(target, args);

        //2.增强功能
        float price = 0.00f;
        if (invoke !=null){
             price = (float) invoke;
            price=price+(25*(int)args[0]);
        }


        return price;
    }
}
--------------------------------------------------------------------------------
 package cha04_dynamic_proxy;

import cha04_dynamic_proxy.factory.UsbFactory;
import cha04_dynamic_proxy.handler.MySellHandller;
import cha04_dynamic_proxy.service.UsbSell;
import java.lang.reflect.Proxy;

public class MainShop {
    public static void main(String[] args) {
        //创建目标对象
        UsbSell  usbSell = new UsbFactory();
       //创建invocationHandller 对象
        MySellHandller handller =new MySellHandller(usbSell);

        //创建代理对象
       UsbSell proxy = (UsbSell) Proxy.newProxyInstance(usbSell.getClass().getClassLoader(),
                                            usbSell.getClass().getInterfaces(),
                                            handller);
        //通过代理对象 执行方法;
        float v = proxy.usbSell(2);
        System.out.println("动过动态代理对象调用方法"+v);

    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QBUxwYsh-1644026320155)(D:\笔记\反射\JDK动态代理.assets\image-20220128140845392.png)]

4.CGLIB动态代理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rgMviLAQ-1644026320156)(D:\笔记\反射\JDK动态代理.assets\image-20220128114615663.png)]

需要导入jar包:核心包和依赖包(spring_core.jar已经集成了这两个包,因此,导入此包即可)

子类是在调用的时候才生成的

使用目标对象的子类的方式实现的代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展,能够在运行时动态生成字节码,可以解决目标对象没有实现接口的问题

缺点:被final或static修饰的类不能用cglib代理,因为它们不会被拦截,不会执行目标对象的额外业务方法

CGLIB(Code Generation Library)是一个开源项目。是一个强大的,高性能,高质量的Code 生成类库,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP。

使用JDK的Proxy实现代理,要求目标类与代理类实现相同的接口。若目标类不存在接口,则无法使用该方式实现。

但对于无接口的类,要为其创建动态代理,就要使用CGLIB来实现**。CGLIB代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。**所以,使用CGLIB生成动态代理要求自标类必须能够被继承,即不能是final的类。

cglib经常被应用在框架中,例如Spring ,Hibernate等。Cglib 的代理效率高于Jdk。对于cglib一般的开发中并不使用。做了一个了解就可以。
ation Library)是一个开源项目。是一个强大的,高性能,高质量的Code 生成类库,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP。

使用JDK的Proxy实现代理,要求目标类与代理类实现相同的接口。若目标类不存在接口,则无法使用该方式实现。

但对于无接口的类,要为其创建动态代理,就要使用CGLIB来实现**。CGLIB代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。**所以,使用CGLIB生成动态代理要求自标类必须能够被继承,即不能是final的类。

cglib经常被应用在框架中,例如Spring ,Hibernate等。Cglib 的代理效率高于Jdk。对于cglib一般的开发中并不使用。做了一个了解就可以。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值