Java-JDK动态代理(AOP)

2021-05-14 16:43:01 浏览数 (1)

什么是动态代理?

使用JDK反射机制,创建对象的能力,创建的是代理类的对象,而不用你创建类,不用写java文件 动态:在程序执行时,调用JDK提供的方法才能创建代理类的对象 JDK动态代理,必须有接口,目标类必须实现接口,没有接口时需要使用cglib动态代理

知道动态代理能做什么 ?

在不改变原来的目标方法功能的前提下,可以在代理中增强自己的功能代码

1.什么是代理

代理:在我们生活之中就有体会,代购,中介,换IP,商家等等

使用代理模式的作用:

  1. 功能增强: 在你原有的功能上,增加了额外的功能,新增加的功能,叫做功能增强
  2. 控制访问: 代理类不上你访问目标…例如商家不让用户访问厂家

实现代理的方式

静态代理

  1. 代理类是自己手工写实现的,自己创建一个JAVA类,表示代理类
  2. 同时你所代理的目标类是确定的

**优点>>**实现简单 容易理解

缺点>> 当你的项目中.目标类和代理类很多的时候,有以下缺点

  1. 当目标类增加了,代理类可能也需要成倍的增加,代理类数量过多
  2. 当你的接口中功能增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多

模拟一个用户购买u盘的行为。 用户是客户端类 商家:代理,代理某个品牌的u盘。 厂家:目标类。 ​ 三者的关系: 用户(客户端)—商家(代理)—厂家(目标) ​ 商家和厂家都是卖u盘的,他们完成的功能是一致的,都是卖u盘。 实现步骤

  1. 创建一个接口,定义卖U盘的方法,表示你的厂家和商家做的事情
  2. 创建厂家类,实现1步骤的接口
  3. 创建厂家类,就是代理,也需要实现1步骤中的接口
  4. 创建客户端类,调用商家的方法买一个

代理类完成的功能:

  1. 目标类中的方法调用
  2. 功能增强

所属我们只有一个代理商,我们实际上可以写多个代理商,

动态代理

什么是动态代理

使用JDK的反射机制,创建对象的能力,创建的时代理类的对象.而不用我们创建类的文件.

什么叫动态?在程序执行时,调用JDK提供的方法才能创建代理类的对象

静态代理和动态代理模式的对比

静态代理中目标很多的时候,可以使用动态代理,避免静态代理的缺点


动态代理中目标类即使很多
  1. 代理类数量可以很少
  2. 当你修改了接口中的方法时…不会影响代理类

动态代理:

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

换句话说:动态代理是一种创建JAVA对象的能力,让你不用创建淘宝类,就能创建代理类对象,

在java中,要想创建对象

  1. 创建类文件,java文件编译为Class文件
  2. 使用构造方法,创建类的对象
动态代理的介绍:

1.动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的,动态代理不需要定义代理类的,java源文件

2.动态代理其就是JDK运行期间,动态创建Class字节码并加载到JVM

3.动态代理的实现运行常用两种方式:使用JDK代理,与通过CGLlB动态代理。

动态代理的实现:
JDK动态代理

JDK动态代理(理解),使用java反射包的类和接口实现动态代理的功能

反射包java.lang.reflect 里面有三个类 : InvocationHandler ,Method, Proxy

  1. 反射: Method类,表示方法,类中的方法,通过method可以执行某个方法
  2. JDK动态代理的实现 反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Method, Proxy. 1) InvocationHandler` InvocationHandler 接口(调用对象); 就是一个方法invoke() invoke(): 表示代理对象要执行的功能代码, 要完成的功能就写在invoke()方法中 代理类完成的功能
    1. 调用目标方法:执行目标方法的功能
    2. 功能增强,在目标方法调用时,增加功能。
方法原型:
代码语言:javascript复制
参数: 
Object proxy:jdk创建的代理对象,无需赋值。
Method method:目标类中的方法,jdk提供method对象的
Object[] args:目标类中方法的参数, jdk提供的。

public Object invoke(Object proxy, Method method, Object[] args)
InvocationHandler接口:
代码语言:javascript复制
表示你的代理要干什么。
怎么用: 1.创建类实现接口InvocationHandler
2.重写invoke()方法, 把原来静态代理中代理类要完成的功能,写在这。

2)Method类:

表示方法的, 确切的说就是目标类中的方法。

代码语言:javascript复制
作用:
通过Method可以执行某个目标类的方法,Method.invoke();
method.invoke(目标对象,方法的参数)
Object ret = method.invoke(service2, "李四");

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

3)Proxy类:

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

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

参数:

  • ClassLoader loader类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader 类a , a.getCalss().getClassLoader(), 目标对象的类加载器
  • Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
  • InvocationHandlerh : 我们自己写的,代理类要完成的功能。

​ 返回值:就是代理对象

代码语言:javascript复制
public static Object newProxyInstance(ClassLoader loader,   Class<?>[] interfaces,   InvocationHandler h)

实现动态代理的步骤:

  1. 创建接口,定义目标类要完成的功能
  2. 创建目标类实现接口
  3. 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能 1.调用目标方法 2.增强功能

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

第一步

代码语言:javascript复制
public interface UsbSell {
   
    float sell(int amount);
}

第二步

代码语言:javascript复制
public class UsbKingFactory implements UsbSell {
   
    @Override
    public float sell(int amount) {
   
        System.out.println("目标类中,执行了sell目标方法");
        return 85.02f;
        
    }
}

我们写了接口类,定义了功能,写了代理类,实现了接口功能,按照以前的操作,现在就需要写一个真正的代理类,创建对象.

第三步: 创建了Invocationhandler实现类,在invoke()方法中完成代理类de对象

  • 调用目标的方法
  • 增强功能
代码语言:javascript复制
public class MyHandle implements InvocationHandler {
   
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
        return null;
    }
}

代理类的实现方法上进行修改

代码语言:javascript复制
//之前的代理类
  public class TaoBao implements usbSell {
   
    // 声明 商家代理的厂家具体是谁
        private UsbKingFactory factory =new UsbKingFactory();

        @Override
    // 实现销售U盘功能
        public float sell(int amount) {
   
    // 向厂家发送订单,告诉厂家,我买了U盘,厂家发货
    // 发送给工厂,我需要的订单,返回报价
            float price = factory.sell(amount);
    // 商家需要加价也就是代理要增加价格
            price = price   25;
    //在目标类的方法调用后,你做的其他功能,都是增强的意思
            System.out.println("淘宝再给你返回一个优惠券,或者红包");
    // 增加的价格
            return price;
        }
    }

调用目标的方法

代码语言:javascript复制
//传入是谁的对象,就给谁创建代理
    public MyHandle(Object target) {
   
        this.target = target;
    }
public Object invoke(Object proxy, Method method, Object[] args){
   
                Object res =null;
            // 向厂家发送订单,告诉厂家,我买了U盘,厂家发货
            // 发送给工厂,我需要的订单,返回报价
// float price = factory.sell(amount);
            res = method.invoke(target,args);       //待执行目标方法,执行后返回值
    
    //增强的方法 res
            }

第四步: 使用Proxy类的静态方法,创建代理对象,并把返回值转换成接口类型

创建一个MainShop类.

代码语言:javascript复制
public class MainShop {
   
    public static void main(String[] args){
    
// 1.创建对象,使用Proxy
// 2.创建目标对象
        UsbSell factory = new UsbKingFactory();
// 3.创建Invocationhandler对象
        InvocationHandler myHandle = new MyHandle(factory);

// 4.创建代理对象
        UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
                factory.getClass().getInterfaces(),
                myHandle);
// 通过代理执行方法
        float price = proxy.sell(1);
        System.out.println("通过动态代理对象,调用方法:"  price);
    }
}

JDK动态代理执行流程

我们先复习一下,Proxy类,实现动态代理的流程,使用返回指定接口的代理类实例,

我们此时debug一下程序,在invok实现类中打一个断点

此时我们再观察,代理对象MyHandler里面的invoke方法的参数

0 人点赞