代理模式——静态代理和动态代理

放上我参考的认为写的很好的博客链接,自己写主要是为了学习一遍,谨慎参考。

链接

为什么要用动态代理呢?当然是静态代理太固定了,对于每一个要代理的对象,我们都要写一个代理类,不够灵活。而动态代理能够在运行时创建一个实现了一组给定接口的新类。

动态代理

代理类的特性

代理类实在程序运行过程中创建的,所有的代理类都扩展于Proxy类,为了履行代理对象的职责,所需的任何附加数据都必须存储在调用处理器中。

另外,所有的代理类都覆盖了Object中的方法,这些方法的调用都会调用调用处理器中的invoke。当然这些方法没有被重新定义。

调用处理器(invocation handler)

代理类要能够实现指定的接口,那么它需要下列方法:

  • 指定接口所需要的全部方法
  • Object类中的全部方法

当然,这些方法的定义自然是不能在运行时定义,这时候就需要用到调用处理器,调用处理器是实现了InvocationHandler接口的类对象。接口中有一个方法:

 

 

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

当调用代理对象的任何方法时,调用处理器的invoke方法都会被调用

  • Object proxy
    被代理对象
  • Method method
    要调用的方法
  • Object[] args
    方法调用时所需要的参数

创建代理对象(Proxy.newProxyInstance)

 

 

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

 

 

  • ClassLoader loader
    类的加载器
  • Class<?>[] interfaces
    需要实现的接口
  • InvocationHandler h
    一个调用处理器
通过该方法可以生成一个代理对象。

使用案例(来自于JAVA核心技术卷一)

这个案例实际上代理的是Integer类以及Comparable接口

TraceHandler.java

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

public class TraceHandler implements InvocationHandler {

    Object target; //要代理的对象

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        /**
         * 打印代理方法的相关信息
         */
        System.out.print(target);
        System.out.print("."+method.getName()+"(");
        System.out.println(Arrays.toString(args)+")");
        return method.invoke(target,args);  //用反射包中的invoke方法调用实际的方法
    }
}

 

 

ProxyTest.java

import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * 创建一个数组用于接受代理了Integer类的代理对象,也就是放置0到1000的数值,但不是Integer类型了。
 * 代理了Comparable接口,接替了代理类(integer)中的compareTo方法,根据我们的调用处理器定义调用invoke
 * 方法时它会打印调用方法的相关信息
 */
public class ProxyTest {
    public static void main(String[] args) {
        Object[] elements = new Object[1000];
        
        for(int i = 0;i< elements.length;i++){
            TraceHandler handler = new TraceHandler(Integer.valueOf(i));
            Object proxyInstance = Proxy.newProxyInstance(Integer.class.getClassLoader(), new Class[]{Comparable.class}, handler);
            elements[i]  = proxyInstance;
        }
        int i = Arrays.binarySearch(elements, 188);  //它会多次调用compareTo方法用于比较大小,而调用compareTo方法实际上会调用invoke方法
        if(i>=0)
            System.out.println(elements[i]);

    }
}


 


 

 

posted @ 2020-12-19 14:27  二仙桥下摸鱼  阅读(116)  评论(0编辑  收藏  举报