Java反射02——动态代理

本文不涉及静态代理,只涉及动态代理,本人见过将动态代理讲的比较好的文章在底部,有兴趣的读者可以移步。
老步骤:

1.什么是动态代理?

通俗的讲,动态代理就是创建一个类的代理对象,当需要访问这个类的某些方法时,可以通过调用代理对象的同名方法,而真正返回的却是这个被代理类所实现的方法。

2.为什么需要动态代理?

a.设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强。

b.我们在使用RPC框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现。

c.Spring的AOP机制就是采用动态代理的机制来实现切面编程。[1]

3.怎么实现动态代理?

想要实现动态代理,需要解决两个问题
(1)如何根据被加载到内存中的被代理类,动态地创建代理类及其对象;
(2)当通过代理类的对象调用方法时,如何动态的调用被代理类中的同名方法;
其实直接以实例来说明是最好的,下面以人和超人为例来讲解:
(1)先创建一个接口,里面有两个抽象方法

interface Human {
    String eat(String food);
    String word();
}

(2)某个类实现这个接口

class SuperMan implements Human{
    @Override
    public String eat(String food) {
        return "超人最爱吃:" + food;
    }

    @Override
    public String word() {
        return "超人专门打怪兽";
    }
}

(3)创建一个专门生成代理类的工厂类
PS:学习动态代理之前一定要理解Java反射机制,不然很多地方没法弄懂

class HumanProxyFactory {
    /**
     * 传入被代理类,返回一个代理类对象
     * @param obj
     * @return
     */
    public static Object createProxy(Object obj) {
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        myInvocationHandler.bind(obj);
        Object proxyInstance = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), myInvocationHandler);
        return proxyInstance;
    }
}

上面最关键的行在于createProxy方法的第四行,也就是如何生成一个代理类的对象(ProxyInstance),这里使用了Java API自带的一个类java.lang.reflect.Proxy,有兴趣的同学的可以直接看JDK的源代码,本人也没看过。Proxy类中存在一个专门创建代理类的函数newProxyInstance,这里面有三个参数,分别是被代理类的类加载器,被代理类实现的接口,以及一个实现了InvocationHandler接口的对象,前两个参数只要掌握了反射就能理解,重点在于第三个参数,所以下面需要自己写一个类来实现InvocationHandler接口。
(4)实现InvocationHandler接口

/**
 * 自己实现一个InvocationHandler接口,当代理类调用自己的方法时,实现的却是被代理类的方法
 */
class MyInvocationHandler implements InvocationHandler {
    Object obj;
    public void bind(Object obj) {
        this.obj = obj;
    }
    /**
     * 传入的是代理类对象,代理类对象的方法,以及该方法中的参数数组
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        /* 这里的返回值,实际上是被代理类调用此方法的返回值,可以为null */
        Object o = method.invoke(obj, args);
        return o;
    }
}

(5)在测试类中检验结果

public class ProxyTest {
    public static void main(String[] args) {
        Human proxy = (Human) HumanProxyFactory.createProxy(new SuperMan());
        String s = proxy.eat("牛排");
        System.out.println(s);
    }
}

结果如下:

以上就是动态代理的基本原理

参考文章

[1]java动态代理实现与原理详细分析

原文地址:https://www.cnblogs.com/dabenhou/p/13921255.html