• 大话设计模式:动态代理模式


    由于静态代理带来扩展性差,可维护性差等缺点,所以就有了动态代理模式。

    下面介绍一下JDK的动态代理:

    动态代理有两个重要的类:

    1. Proxy类:

    provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

    它是所有动态代理类的父类,同时提供一个静态方法来创建代理类的实例,方法名叫:newProxyInstance

    2. InvocationHandler接口:

    Processes a method invocation on a proxy instance and returns the result.  This method will be invoked on an invocation handler when a method is invoked on a proxy instance that it is associated with.

    其中只有一个方法invoke,大致是:在代理类的实例中调用真实方法,并返回结果。

    有三个参数:

    1. proxy:代理对象的实例

    2. method: 通过它可以调用真实方法

    3. args:传过来的参数

    动态代理的简单应用:

    1. 创建实现InvocationHandler接口的代理类:

    /**
     * description 实现InvocationHandler接口的动态代理类
     *
     * @author 70KG
     * @date 2018/8/2
     */
    public class ProxyClassBeans implements InvocationHandler {
    
        /**
         * 被代理的对象
         **/
        private Object tar;
    
        /**
         * 利用反射来调用目标方法
         **/
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            doBefore();
            Object invoke = method.invoke(tar, args);
            doAfter();
            return invoke;
        }
    
        /** 绑定该类实现的所有接口,取得代理类 **/
        public Object getProxyInstance() {
            return Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);
        }
    
        // ===================动态代理类中的增强方法========================
    
        public void doBefore() {
            System.out.println("在国外寻找优质的货源。");
        }
    
        public void doAfter() {
            System.out.println("精包装安全邮寄回国内。");
        }
    
        // ===========================get/set=============================
    
    
        public Object getTar() {
            return tar;
        }
    
        public void setTar(Object tar) {
            this.tar = tar;
        }
    }

    2. 接口

    /**
     * description
     *
     * @author 70KG
     * @date 2018/8/1
     */
    public interface IBusinessA {
    
        /**
         * Description: 卖包的业务接口
         * Author:70KG
         * Param [brand] 品牌
         * Return void
         * Date 2018/8/1 9:46
         */
        void saleBag(String brand);
    
    }
    /**
     * description
     *
     * @author 70KG
     * @date 2018/8/1
     */
    public interface IBusinessB {
    
        /**
         * Description: 卖手表的业务接口
         * Author:70KG
         * Param [brand] 品牌
         * Return void
         * Date 2018/8/1 9:48
         */
        void saleWatch(String brand);
    
    }

    3. 实现规定接口的被代理类

    /**
     * description
     *
     * @author 70KG
     * @date 2018/8/1
     */
    public class CompanyA implements IBusinessA {
    
        @Override
        public void saleBag(String brand) {
            System.out.println("从国外A公司买到一款" + brand + "牌的包。");
        }
    
    }
    /**
     * description
     *
     * @author 70KG
     * @date 2018/8/1
     */
    public class CompanyB implements IBusinessB {
    
        @Override
        public void saleWatch(String brand) {
            System.out.println("从国外B公司买到一款" + brand + "牌的手表。");
        }
    
    }

    4. 测试方法:

    /**
     * description
     *
     * @author 70KG
     * @date 2018/8/2
     */
    public class MainTest {
    
        public static void main(String[] args) {
            ProxyClassBeans proxyClassBeans = new ProxyClassBeans();
    
            IBusinessA companyA = new CompanyA();
            proxyClassBeans.setTar(companyA);
            IBusinessA instance1 = (IBusinessA) proxyClassBeans.getProxyInstance();
            instance1.saleBag("Gucci");
    
            System.out.println("=================================");
    
            IBusinessB companyB = new CompanyB();
            proxyClassBeans.setTar(companyB);
            IBusinessB instance2 = (IBusinessB) proxyClassBeans.getProxyInstance();
            instance2.saleWatch("Tissot");
        }
    
    }

    5. 运行结果:

    在国外寻找优质的货源。
    从国外A公司买到一款Gucci牌的包。
    精包装安全邮寄回国内。
    =================================
    在国外寻找优质的货源。
    从国外B公司买到一款Tissot牌的手表。
    精包装安全邮寄回国内。

    6. JDK的动态代理只能代理接口,不能代理具体的类,通过JDK生成的代理类:public final class $Proxy0 extends Proxy implements YourInterface {},Java只支持单继承,所以不能代理具体类了。

    相比静态代理,当业务扩展或者参数变动的时候,我们不需要改动代理类,只需要生成相应的代理实例,并传入接口需要的参数就好了,这样扩展性和维护性大大提高。

    动态代理源码的简单分析:

    debug跟进生成的代理类

    这个代理类的名字很特殊,跟一下源码

    跟进 Class<?> cl = getProxyClass0(loader, intfs);

    跟进get方法

    跟进apply方法

    动态代理的源码大概就这么多了。

  • 相关阅读:
    701. 二叉搜索树中的插入操作
    【ceph | 运维】 部署mgr
    【cpeh | 运维】mon相关命令
    【Leetcode】144. 二叉树的前序遍历
    【Linux】Linux中查看某个软件的安装路径
    【Leetcode】100. 相同的树
    【Leetcode】145. 二叉树的后序遍历
    【Leetcode】94. 二叉树的中序遍历
    redis学习04Redis的主从架构
    RabbitMQ学习02安装与配置(Ubuntu系统)
  • 原文地址:https://www.cnblogs.com/zhangjianbing/p/9406576.html
Copyright © 2020-2023  润新知