如何实现动态代理和静态代理(简单易懂)

1. 使用原因
最最最主要的原因就是,在不改变目标对象方法的情况下对方法进行增强,比如,我们希望对方法的调用增加日志记录,或者对方法的调用进行拦截,等等…
最最最常见的就是AOP了,在环绕通知中,可以改变目标方法的返回结果和执行过程,这就是使用了动态代理。
2. 原理
动态代理和静态代理,区别在于有没有重新加载内存,为什么这么说呢,可以从实现中可以看出,静态代理是通过实现同一接口,在执行目标对象方法的时候进行处理,很直观,不会重新加载内存,而动态代理,动态生成代理类字节码,然后利用类加载器(classloader)加载到内存中,并且编译,是生成了实实在在的新的对象,这也是动态一词的来源。
具体可以参考:https://blog.csdn.net/lwlw20000/article/details/52710821
3. 实现

//代理类和目标对象属于同一类,才叫做代理
public interface IPerson {
    void say();
}
public class Man implements IPerson{
    @Override
    public void say() {
         System.out.println("man say");
    }
}
3.1静态代理
	public class ManProxy implements IPerson{
    private IPerson target;
    public IPerson getTarget() {
        return target;
    }
    public ManProxy setTarget(IPerson target) {
        this.target = target;
        return this;
    }
    @Override
    public void say() {
        if (target != null) {
           System.out.println("man say invoked at : " + System.currentTimeMillis());
            target.say();
        }
    }
}

从上面的代码中可以看出,ManProxy执行了Man对象的方法(或者IPerson实现类的方法)只是加以修饰,最后我们通过调用ManProxy对象say方法来执行Man对象的say方法。这也是动态代理的雏形。
3.2动态代理
首先创建Handler

public class NormalHandler implements InvocationHandler {
    private Object target;
    public NormalHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        L.d("man say invoked at : " + System.currentTimeMillis());
        method.invoke(target, args);
        return null;
    }
}
测试
public static void main(String[] args) {
		Man man = new Man();
		NormalHandler normalHandler = new NormalHandler(man);
		IPerson iPerson = (IPerson) Proxy.newProxyInstance(IPerson.class.getClassLoader(),new Class[] {IPerson.class},normalHandler);
		iPerson.say();
}

关于InvocationHandler官方文档的解释是

	{@code InvocationHandler} is the interface implemented by
    the <i>invocation handler</i> of a proxy instance.
    <p>Each proxy instance has an associated invocation handler.
    When a method is invoked on a proxy instance, the method
    invocation is encoded and dispatched to the {@code invoke}
    method of its invocation handler.

可以看出每一代理实例,都有一个关联的调用处理程序,在调用代理类的方法时,方法调用被编码和发布的时候会调用Handler的invoke方法。
关于Proxy
Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。

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

这个方法的作用就是创建一个代理类对象,它接收三个参数,我们来看下几个参数的含义:
loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。

猜你喜欢

转载自blog.csdn.net/qq_35275077/article/details/88219368