• 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动态代理实现与原理详细分析

  • 相关阅读:
    Oracle Instant Client 配置
    释放至强平台 AI 加速潜能 汇医慧影打造全周期 AI 医学影像解决方案
    Analytics Zoo Cluster Serving自动扩展分布式推理
    基于时序数据,推动智能运维发展
    助力用户选择更优模型和架构,推动 AI机器视觉落地智能制造
    英特尔与 Facebook 合作采用第三代英特尔® 至强® 可扩展处理器和支持 BFloat16 加速的英特尔® 深度学习加速技术,提高 PyTorch 性能
    如何无缝地将人工智能扩展到分布式大数据
    Burger King使用RayOnSpark进行基于实时情景特征的快餐食品推荐
    如何往Spark社区做贡献,贡献代码
    开源:从社区到商业化
  • 原文地址:https://www.cnblogs.com/dabenhou/p/13921255.html
Copyright © 2020-2023  润新知