代理模式-JDK与cglib的动态代理(一)

        2020年受疫情影响,各位小伙伴们困在家里出大门都是一种奢望,人都要憋出病了,作者都快疯了,都是泪。这样严峻时刻我们生活必须品都是小区代购帮我们代买。这种情况,代购就是购买行为的执行者,而我们就是被代理对象。这就满足了代理模式应用场景的三个必要条件:

        1.两个角色:执行者(采购),被代理对象(小伙伴)

        2.执行者必须有被代理对象的引用(登记采购信息)

        3.必须要做的事(废话,不买人就没了)

下面我们看看jdk与cglib是如何做到的

JDK动态代理

首先我们先定义一个接口Person

public interface Person {
     void shop();
}

我们的小伙伴出场,他要shop

public class Friend implements Person {
     
     private String name = "小伙伴";
     
     private String adress = "火星";
     
     private String material = "火腿肠";
     @Override
     public void shop() {
          System.out.println("我叫"+this.name+",我住在"+this.adress+",我要买"+this.material);
     }
}

但是我们的小伙伴不能出门,也就买不了火腿肠。这是采购人员来帮我们了

public class Caigou implements InvocationHandler {
     private Person target;//引用
    
        //获取引用 返回新的代理类实例
     public Object getInstantce(Person target) throws  Exception {
          this.target = target;
          Class<?> clazz = target.getClass();
          return  Proxy.newProxyInstance(clazz.getClassLoader(),  clazz.getInterfaces(), this);
     }
     @Override
     public Object invoke(Object arg0, Method method ,  Object[] args) throws Throwable {
          System.out.println("我是采购");
          //反射调用
          method.invoke(this.target,args);
          System.out.println("开始采购");
          System.out.println("采购完成");
          return null;
     }
}

使用jdk的动态代理需要实现InvocationHandler。代理应用场景三个条件。我们有了两个对象,在newProxyInstance()中被代理类的引用也给了代理。newProxyInstance返回了指定接口新的代理类,第一个参数需要类加载器,第二个也就是我们指定的接口,第三个需要一个InvocationHandler也Caigou。我们一并将这个返回打印看看。

public class TestShop {
     public static void main(String[] args) {
          try {
              Person person  = (Person)new  Caigou().getInstantce(new Friend());
              System.out.println(person.getClass());
              person.shop();
          } catch (Exception e) {
              e.printStackTrace();
          }
     }
}
class com.sun.proxy.$Proxy0
我是采购
我叫小伙伴,我住在火星,我要买火腿肠
开始采购
采购完成

代理成功了,但是我们打印的Person的类对象为什么是class com.sun.proxy.$Proxy0

我们获取$Proxy0的字节码一探究竟。

 public static void main(String[] args) {
          try {
              Person person  = (Person)new  Caigou().getInstantce(new Friend());
              System.out.println(person.getClass());
              person.shop();
              //输出字节码文件
             byte[] data =  ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
              FileOutputStream fos = new  FileOutputStream("输出$Proxy0.class文件地址");
              fos.write(data);
              fos.close();
          } catch (Exception e) {
              e.printStackTrace();
          }
     }

用反编译工具查看。

public final class $Proxy0 extends Proxy implements  Person {
     private static Method m1;
     private static Method m2;
     private static Method m3;
     private static Method m0;
     public $Proxy0(InvocationHandler var1) throws  {
      super(var1);
   }
     public final boolean equals(Object var1) throws  {
      try {
         return (Boolean)super.h.invoke(this, m1, new  Object[]{var1});
      } catch (RuntimeException | Error var3) {
         throw var3;
      } catch (Throwable var4) {
         throw new UndeclaredThrowableException(var4);
      }
   }
     public final String toString() throws  {
      try {
         return (String)super.h.invoke(this, m2,  (Object[])null);
      } catch (RuntimeException | Error var2) {
         throw var2;
      } catch (Throwable var3) {
         throw new UndeclaredThrowableException(var3);
      }
   }
     public final void shop() throws  {
      try {
         //super.h在调用newProxyInstance的第三个参数Caigou,这里实际上就是在执行Caigou的invoke方法。
         super.h.invoke(this, m3, (Object[])null);
      } catch (RuntimeException | Error var2) {
         throw var2;
      } catch (Throwable var3) {
         throw new UndeclaredThrowableException(var3);
      }
   }
     public final int hashCode() throws  {
      try {
         return (Integer)super.h.invoke(this, m0,  (Object[])null);
      } catch (RuntimeException | Error var2) {
         throw var2;
      } catch (Throwable var3) {
         throw new UndeclaredThrowableException(var3);
      }
   }
     static {
          try {
              m1 =  Class.forName("java.lang.Object").getMethod("equals",  Class.forName("java.lang.Object"));
              m2 =  Class.forName("java.lang.Object").getMethod("toString");
              m3 =  Class.forName("com.*.proxy.jdk.Person").getMethod("shop");
              m0 =  Class.forName("java.lang.Object").getMethod("hashCode");
          } catch (NoSuchMethodException var2) {
              throw new  NoSuchMethodError(var2.getMessage());
          } catch (ClassNotFoundException var3) {
              throw new  NoClassDefFoundError(var3.getMessage());
          }
     }
}

$Proxy0继承了Proxy,实现了Person。显然main方法中 person.shop()执行的是$Proxy0的shop()了,里面就只有一句代码,super.h.invoke(this, m3, (Object[])null); super.h就是在调用newProxyInstance的第三个参数给的this也就是Caigou,那这里实际上就是在执行Caigou的invoke方法了。

jdk的动态代理基本步骤:

  1. 获取被代理对象的引用与所实现的接口
  2. jdk动态生成类继承了Proxy 实现获取的接口
  3. 动态加载这个新的类
  4. 执行代理操作

总结jdk动态代理过程:字节码重组

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值