Java 代理模式

  1. 什么是代理?
代理模式(Proxy)是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能,如添加权限,访问控制和审计等功能。
  1. 什么时候使用代理?
当我们需要在某些方法中额外增加功能但不破坏原有代码结构的情况下就可以使用代理。
  1. 如何创建代理对象?
    通过 Proxy.newProxyInstance 方法创建
    其中,该方法中一共有三个参数:
    1. 一个类加载器,如果使用默认的类加载器,则设置为 null
    2. 一个 Class类的数组,其中数组当中的元素为需要监听的接口
    3. 一个实现了 InvocationHandler 接口的对象。
      返回值为创建好的代理对象。
  2. 如何应用代理?
    以下代码是基于 JDK 11 实现
package CoreJavaFundamentals.Chapter06.proxy;

import java.lang.reflect.*;
import java.util.*;

/**
 * ProxyTest class
 *
 * @date 2020/2/14
 */
public class ProxyTest {

    public static void main(String[] args) {
        // 创建一个数组,用来保存代理对象
        var elements = new Object[1000];
        for (var i = 0; i < elements.length; i++) {
            var value = i + 1;
            var handler = new TraceHandler(value);
            var interfaces = new Class[]{Comparable.class};
            elements[I] = Proxy.newProxyInstance(null, interfaces, handler);
        }
        var key = new Random().nextInt(elements.length) + 1;
        // 通过二分查找查找元素。
        var result = Arrays.binarySearch(elements, key);
        if (result >= 0) {
            System.out.println(elements[result]);
        }
    }
}

/**
 * 创建一个实现调用处理器(InvocationHandler)接口的类,其中的 invoke 方法为当代理对象触发了接口数组当中的方法的时候,该方法就会先于原调用方法执行。
 */
class TraceHandler implements InvocationHandler {
    // 保存
    private Object target;

    public TraceHandler(Object target) {
        this.target = target;
    }

    /**
     * 代理对象调用方法的时候触发该方法
     * @param proxy 代理对象
     * @param method 代理对象调用的方法对象
     * @param args 代理对象调用的方法保存的参数
     * @return 原对象调用方法后的返回值
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.print(target);
        System.out.print(“.” + method.getName() + "(");
        if (Objects.nonNull(args)) {
            for (var i = 0; i < args.length; i++) {
                System.out.print(args[i]);
                if (i < args.length - 1) {
                    System.out.print(", ");
                }
            }
        }
        System.out.println(")");
        // 如果还想触发原对象的方法的话,需要手动调用 method.invoke 方法来指定调用对象和调用参数
        // 返回值即为代理对象触发原方法的返回值。
        return method.invoke(target, args);
    }
}

这段代码的执行结果如下:
Java 代理模式_第1张图片
为什么会出现这个结果?分析一下源码看看吧。
1. 为什么会打印 xxx.compareTo(yyy)
在执行Arrays.binarySearch方法的时候,在这个地方遇到了compareTo方法。
Java 代理模式_第2张图片
在执行到这的时候,由于我们传递的数组 elements 是代理类的数组,其中该代理类对象创建的时候指定了该对象会实现 Comparable 接口当中的方法。于是,在执行到蓝色行的时候,就会先触发实现了 InvocationHandler 类当中的 invoke 方法。于是,就打印出: xxx.compareTo(yyy) 的结果。
2. 为什么会打印 xxx.toString()

打印出 compareTo 这个字符串我还是能理解,因为在创建代理对象的时候设置了实现哪些接口的参数,但是 toString 方法并不是接口定义的方法。怎么会显示?

这是因为在创建代理对象的时候,代理对象也会监听所有 Object 类的所有方法,也就是说,invoke方法不仅会触发所有接口数组当中的方法,同样,所有 Object 类下的方法也会被触发。

参考链接:https://www.jianshu.com/p/8ccdbe00ff06

你可能感兴趣的:(Java,基础)