动态代理简介

代理是一种常用的设计模式,其目的就是为真实对象提供一个代理对象以控制对真实对象的访问。代理类负责为委托类(被代理类、真实类)预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
动态代理类.png
为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象

简单的动态代理实例

Work接口需要实现work函数

public interface Work {
    public String work();
}

Hacker类实现了Work接口

public class Hacker implements Work{
    @Override
    public String work() {
        System.out.println("my work is B");
        return "Hacker";
    }
}

WorkHandler用来处理被代理对象,它必须继承InvocationHandler接口,并实现invoke方法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class WorkHandler implements InvocationHandler{
    //代理类中的真实对象
    private Object obj;
    //构造函数,给我们的真实对象赋值
    public WorkHandler(Object obj) {
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在真实的对象执行之前我们可以添加自己的操作
        System.out.println("before invoke。。。");
        //java的反射功能,用来调用obj对象的method方法,传入参数为args
        Object invoke = method.invoke(obj, args);
        //在真实的对象执行之后我们可以添加自己的操作
        System.out.println("after invoke。。。");
        return invoke;
    }
}

在Test类中通过Proxy.newProxyInstance进行动态代理,这样当我们调用代理对象proxy对象的work方法的时候,实际上调用的是WorkHandler的invoke方法。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
    public static void main(String[] args) {
        //要代理的真实对象
        Work people = new Hacker();
        //代理对象的调用处理程序,我们将要代理的真实对象传入代理对象的调用处理的构造函数中,最终代理对象的调用处理程序会调用真实对象的方法
        InvocationHandler handler = new WorkHandler(people);
        /**
         * 通过Proxy类的newProxyInstance方法创建代理对象,我们来看下方法中的参数
         * 第一个参数:people.getClass().getClassLoader(),使用handler对象的classloader对象来加载我们的代理对象
         * 第二个参数:people.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,这样代理对象就能像真实对象一样调用接口中的所有方法
         * 第三个参数:handler,我们将代理对象关联到上面的InvocationHandler对象上
         */
        Work proxy = (Work)Proxy.newProxyInstance(handler.getClass().getClassLoader(), people.getClass().getInterfaces(), handler);
        System.out.println(proxy.work());
    }
}

看一下输出结果,我们再没有改变Hacker类的前提下通过代理Work接口,实现了work函数调用的重写。

before invoke。。。
my work is B
after invoke。。。
Hacker

动态代理的步骤

  • 创建被代理的类(委托类、真实类)(Hacker)及其接口(Work)
  • 创建一个实现接口InvocationHandler的类(WorkHandler),它必须实现接口的invoke方法
  • 通过Proxy的静态方法newProxyInstance(), 创建一个代理对象(proxy), Work proxy
    =(Work)Proxy.newProxyInstance(loader,interfaces,handler);
  • 通过代理对象(proxy)调用 委托类对象( work)的方法
Last modification:April 20th, 2020 at 10:12 am