设计模式 - 代理模式2 - 动态代理

本文深入探讨动态代理的概念,对比静态代理,详细讲解其优势及多种实现方式,包括JDK自带的动态代理类、javaassist字节码操作库、CGLIB和ASM。通过具体代码示例,展示如何在Java中利用动态代理简化程序设计。

动态代理(dynamic proxy)

1. 什么是动态代理

​ 动态代理比起静态代理更加重要,因为动态代理使用的范围比起静态代理更广,所以也更加普遍。需要好好地进行研究。

​ 动态代理的本意是,在以后的程序的进行中呢,代理类的内容不需要自己去编写了。

​ 在编写静态代理类的时候,我们需要编写两个类,一个真实角色类,一个代理角色类。

​ 在动态代理中,代理类的生成,都是交给工具来实现的。所以称为动态生成代理类。

2. 动态代理(动态生成代理类)的几种方式:

  • JDK自带的动态代理类
  • javaassist 字节码操作库实现
  • CGLIB
  • ASM(底层使用指令,可维护性差)

3. 动态代理相比较静态代理的优点

  • 抽象角色中(接口)声明的所有方法都被转移到调用处理器一个几种的方法中处理,这样我们可以更加灵活和统一的处理众多的方法。

3. 动态代理(JDK 自带的实现)

  • JDK 自带的动态代理

    • java.lang.reflect.proxy

      • 作用:动态生成代理类和对象
    • java.lang.reflect.InvocationHandler (处理器接口)

      • 可以通过 invoke 方法实现对真实角色的代理访问。
      • 每次通过 Proxy 方法生成代理类对象时都要指定对应的处理器对象
      Star realStar = new RealStar();
      StarHandler handler  = new StarHandler(readStar);
      Star proxy = (Star) Proxy.newProxyInstance(Class.Loader.getSystemClassLoader(), new Class[]{Star.class}, handler);
      proxy.sing();
      

      这里以之前的歌手和经纪人之间的关系做类比。

      首先,realStar 是我们的真实角色,下面的 Handler 是处理器接口,将真实角色传入进去。StarHandler 主要用来作我们的流程控制。然后呢,通过 Proxy 生成一个代理对象。然后去调用代理对象的方法 Proxy.sing()。在 Proxy.newProxyInstance() 方法中,传入了类加载器 Class.Loader.getSystemClassLoader(), 使用我们系统默认的;然后还有 Star.class 这个接口,我们将接口传入 Class[] (因为生成的不止一个),这个代理类就会自动地实现这个接口,最后一个参数是处理器。这是一个固定的套路

4. 使用代码实现动态代理

还是以歌手和经纪人之间的关系为类比:

  • 首先还是先创建抽象角色:

    package com.designmodel.proxy.dynamicproxy;
    
    public interface Star {
        /**
         * 面谈
         */
        void confer();
    
        /**
         * 签合同
         */
        void signContract();
    
        /**
         * 订票
         */
        void bookTicket();
    
        /**
         * 唱歌
         */
        void sing();
    
        /**
         * 收钱
         */
        void collectMoney();
    }
    
    
  • 然后依据抽象角色创建真实角色:

    package com.designmodel.proxy.dynamicproxy;
    
    public class RealStar implements Star {
        public void confer() {
            System.out.println("RealStar.confer()");
        }
    
        public void signContract() {
            System.out.println("RealStar.signContact()");
        }
    
        public void bookTicket() {
            System.out.println("RealStar.bookTicket()");
        }
    
        public void sing() {
            System.out.println("RealStar(周杰伦本人).sing()");
        }
    
        public void collectMoney() {
            System.out.println("RealStar.collectMoney()");
        }
    }
    
  • 然后创建处理器:

    package com.designmodel.proxy.dynamicproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class StarHandler implements InvocationHandler {
    
        Star realStar;
    
        public StarHandler(Star realStar) {
            this.realStar = realStar;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object object = null;
            // 所有的方法调用都会从这里进入, 只有当调用的方法是 sing 方法,我们才会让
            // 歌手去唱歌
            System.out.println("真正的方法执行前:");
            System.out.println("面谈,签合同,预付款,订机票");
            if(method.getName().equals("sing")) {
                object = method.invoke(realStar, args);
            }
            System.out.println("唱完歌之后:");
            System.out.println("收尾款");
            return object;
        }
    }
    
    
  • 最后在客户端中进行调用:

    package com.designmodel.proxy.dynamicproxy;
    
    import java.lang.reflect.Proxy;
    
    public class Client {
        public static void main(String[] args) {
            Star realStar = new RealStar();
            StarHandler handler = new StarHandler(realStar);
            // 这里返回了一个 Star 对象
            Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler);
            // 运行时,我们会发现,所有的方法调用,最终都会进入 StarHandler.invoke() 方法中
            // 这样我们就可以进行流程的控制了。
            proxy.sing();
        }
    }
    
    
  • 运行结果:

    /*
    * 真正的方法执行前:
    * 面谈,签合同,预付款,订机票
    * RealStar(周杰伦本人).sing()
    * 唱完歌之后:
    * 收尾款
    */
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值