JDK实现动态代理

JDK实现动态代理

思维导图:点击打开

1.代理模式概念

代理模式是指:为其他对象提供一种代理用以控制这个对象的访问。

在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标类之间起到中介的作用。——————百度百科《代理模式》

         代理对象
客户端---->中介---->目标对象

生活中的例子:

  1. 房产中介
  2. 代购
  3. 媒婆

2.代理模式作用

2.1控制访问

在代理中控制客户端能否调用目标对象的方法。

2.2增强功能

完成目标对象的调用时,附加一些额外功能,这些额外功能就是增强功能。

比如媒婆要求中介费用

3.代理模式分类

代理模式分为静态代理和动态代理

3.1静态代理

3.1.1描述

静态代理是指:代理类在程序运行前就已经定义好了.java源文件,代理类和目标类的关系在程序运行前就已经确立了。在程序运行前代理类就已经编译成了.class文件。

3.1.2优缺点

1.优点

  1. 容易理解
  2. 使用比较方便

2.缺点

  1. 目标类较多时,会产生大量代理类

  2. 当接口改变时,影响的目标类较多

3.2动态代理

3.2.1描述

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

动态代理其实就是JDK运行期间,动态创建class字节码文件并加载到JVM

3.2.2优点

  1. 不用创建类文件
  2. 当修改了接口中的方法时,不会影响代理类
  3. 不用给不同的目标随时创建代理

3.2.3常用实现方式

1.JDK动态代理:

  1. 使用java反射包中的类和接口实现动态代理的功能。
  2. 反射包:java.lang.reflect
  3. 使用的类:
    1. InvocationHandler
    2. Method
    3. Proxy

2.CGLIB动态代理:

  1. cglib时第三方的工具库,用于创建代理对象。
  2. cglib的原理是继承,cglib通过继承目标类,创建其子类,在子类中重写父类中同名的方法,实现功能的修改。
  3. 因为cglib需要继承目标类,所以要求目标类不能是final的,方法也不能是final的。
  4. cglib对于目标类的要求比较宽松,只要能继承就可以。
  5. cglib在很多框架中使用,如mybatis,spring框架。

4.JDK的动态代理

jdk的动态代理是基于Java的反射机制实现的。使用jdk中的接口和类来实现代理对象的动态创建。

jdk的动态代理要求目标对象必须实现接口。

4.1 InvocationHandler,Method和Proxy

4.1.1InvocationHandler接口

InvocationHandler接口叫做调用处理器,该接口只有一个抽象方法:invoke()。

在InvocationHandler接口的实现类中,实现调用目标方法并增强功能的语句就写在invoke()方法里。

public Object invoke(Object proxy, Method method, Object[] args)

proxy:代表生成的代理对象

method:代表目标方法

args:代表目标方法的参数

这三个参数都是jdk运行是赋值的,无需程序员给出。

4.1.2Method类

InvocationHandler接口的invoke()方法中,第二个参数就是Method类对象,该类中也有一个invoke()方法,可以调用目标方法。这两个invoke()方法虽然同名,但是没有关系。

public Object invoke(Object obj, Object... args)

该方法的作用是:调用执行obj对象所属类的方法,该方法由调用者Method对象确定。

在代码中,一般写法为:

method.invoke(target,args);

其中,method是InvocationHandler接口invoke方法的第二个参数。

4.1.3Proxy类

通过JDK的java.lang.reflect.Proxy类实现动态代理,会使用其静态方法newProxyInstance(),根据目标对象、业务接口以及调用处理器,自动生成一个动态代理对象。

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

loader:目标类的类加载器,通过目标对象的反射可以获取【目标对象.getClass().getClassLoader()】

interfaces:目标类实现的接口数组,同样可以通过目标对象的反射获取【目标对象.getClass().getInterfaces()】

h:调用处理器,也就是InvocationHandler接口实现类对象

4.2动态代理实现步骤

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

4.2.1创建目标接口

定义目标类要完成的功能

package com.tsccg.service;

/**
 * @Author: TSCCG
 * @Date: 2021/09/03 16:31
 * 目标接口
 */
public interface PhoneSell {
    float sell(int amount);
}

4.2.2创建目标类来实现目标接口

package com.tsccg.factory;

import com.tsccg.service.PhoneSell;

/**
 * @Author: TSCCG
 * @Date: 2021/09/03 16:40
 * 目标类
 */
public class PhoneFactory implements PhoneSell {
    @Override
    public float sell(int amount) {
        System.out.println("目标类,执行目标方法");
        return 50.0F;
    }
}

4.2.3创建InvocationHandler接口的实现类

在invoke方法中完成代理类的功能

  1. 调用目标类的方法
  2. 增强功能
package com.tsccg.handler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @Author: TSCCG
 * @Date: 2021/09/03 16:43
 * 必须实现代理类要做的功能
 * 1.调用目标类方法
 * 2.增强功能
 */
public class MySellHandler implements InvocationHandler {
    //代表目标对象
    private Object target = null;

    public MySellHandler(Object target) {
        //给目标对象赋值
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //1.执行目标类方法
        Object result = null;
        result = method.invoke(target,args);
        //2.增强功能,在目标类方法调用后,所做的其他功能都是增强功能
        if (result != null) {
            Float price = (Float)result;
            price += 25;
            result = price;
        }
        System.out.println("商家,增强服务:优惠券");
        //3.返回增强的价格
        return result;
    }
}

4.2.4使用Proxy类的静态方法,创建代理对象

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

package com.tsccg;

import com.tsccg.factory.PhoneFactory;
import com.tsccg.handler.MySellHandler;
import com.tsccg.service.PhoneSell;

import java.lang.reflect.Proxy;

/**
 * @Author: TSCCG
 * @Date: 2021/09/03 17:04
 * 使用Proxy类的静态方法创建代理对象
 */
public class MainShop {
    public static void main(String[] args) {
        //1.创建目标对象
        PhoneSell factory = new PhoneFactory();
        //2.创建InvocationHandler接口实现类对象,传入目标对象
        MySellHandler handler = new MySellHandler(factory);
        //3.创建代理对象
        PhoneSell proxy = (PhoneSell)Proxy.newProxyInstance(factory.getClass().getClassLoader(),
                factory.getClass().getInterfaces(),handler);
        //4.通过代理对象执行目标方法
        float price = proxy.sell(1);
        System.out.println("通过动态代理对象调用方法:" + price);
    }

}

执行结果:

目标类,执行目标类的方法
商家,增强服务:优惠券
通过动态代理对象调用方法:75.0
posted @ 2021-09-03 18:17  TSCCG  阅读(2207)  评论(0编辑  收藏  举报