动态代理

动态代理

概述

动态代理是在不断的需求变更中,逐渐过渡到具有代理能力和动态性的模式。为什么需要代理呢?找代理当然是为了完成我们想要完成的事。比如说想访问国外的网站,可以通过代理服务器将请求转发给目的主机,再将响应返回给客户端,如果能命中缓存还能更快一些。。总的来说,代理可以更加专业的处理问题,而作为被代理的对象可以更专注于做自己的事情。

说到代理不可避免要把静态代理和动态代理作比较,基本上静态代理能做的动态代理也能做。静态代理需要对每一个目标类都编写一个代理类,如果当前系统有成百上千的类,那么工作量是很大的。在这种场景下就要引出动态代理。动态代理就是在程序运行的过程中,动态生成代理类对象。动态代理实现了原有对象的增强,最关键的一点是,不用修改已经编写好的代码。。另外动态代理很灵活,也就是当这个需求改变时,可以删除或者修改这部分的代理,不会对原有的代码产生影响。

JDK原生动态代理

JDK动态代理一般依靠两个核心类实现,分别是InvocationHandler和Proxy
InvocationHandler是一个接口,该接口中定义了一个抽象方法invoke(),invoke方法需要接收三个参数,分别是代理类对象,Method对象,参数数组。Proxy主要的两个静态方法,getProxyClass得到一个代理类和newProxyInstance返回一个代理类对象。

动态代理的实现
  public interface Message {
      void sendMsg();
  }
  public class MessageImpl implements Message{
      @Override
      public void sendMsg() {
          System.out.println("jdk 实现动态代理");
      }
  }
  public class MyInvocationHandler implements InvocationHandler {
      private Message message;
      public MyInvocationHandler(Message message){
          this.message = message;
      }
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          System.out.println("before agent........");
          Object obj = method.invoke(message, args);
          System.out.println("after agent.........");
          return obj;
      }
  }
  public class DynamicAgentTest {
      public static void main(String[] args) {
          MessageImpl message = new MessageImpl();
          Message o = (Message) Proxy.newProxyInstance(message.getClass().getClassLoader(),
                  message.getClass().getInterfaces(),
                      new MyInvocationHandler(message));
          o.sendMsg();
      }
  }
动态代理的原理分析

从表面上看,当代理类对象调用自己内部的方法时,会自动跳转到InvocationHandler对象的invoke方法去执行。invoke方法可以实现对真实对象方法调用的增强。
代理对象调用方法时为什么会到自定义的InvocationHandler执行invoke方法呢?
代理对象是通过Proxy的静态方法newProxyInstance()创建的,那newProxyInstance中到底发生了什么事呢?

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        //动态代理最核心的方法
        Class<?> cl = getProxyClass0(loader, intfs);

        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

newProxyInstance()返回持有InvocationHandler实例对象的代理类对象,关键的一步getProxyClass0()怎么得到Class对象

  private static Class<?> getProxyClass0(ClassLoader loader,
                                             Class<?>... interfaces) {
          if (interfaces.length > 65535) {
              throw new IllegalArgumentException("interface limit exceeded");
          }
      	//Class对象可以由ProxyClassFactory直接创建,或者在缓存中获取
          return proxyClassCache.get(loader, interfaces);
      }
  private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
          proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

如果给定接口的代理类已经存在,那么返回副本,否则,通过ProxyClassFactory创建代理类。proxyClassCache是关键的变量,Class对象的获取直接和proxyClassCache相关,所以单独谈谈这个属性。proxyClassCache作为Proxy类的静态私有域,在Proxy类被加载时生成全局唯一的WeakCache实例。proxyClass不直接存储,它内部定义了一个私有的成员变量map,map类型是ConcurrentMap<Object, ConcurrentMap<Object, Supplier>>, 键是由loader区别的CacheKey,value存放的ConcurrentMap<Object, Supplier>可以是以下两种类型,根据类加载器和接口对应Class对象工厂或者CacheValue。

  final class WeakCache<K, P, V> {
      public V get(K key, P parameter) {
              Objects.requireNonNull(parameter);

          	//清除过期的缓存
              expungeStaleEntries();

          	//cacheKey作为一级缓存的键。当key被回收时,cacheKey会加入到refQueue,用于清除过期缓存。
              Object cacheKey = CacheKey.valueOf(key, refQueue);

              ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);

              if (valuesMap == null) {
                  //缓存为空,通过CAS方式放入数据
                  ConcurrentMap<Object, Supplier<V>> oldValuesMap
                      = map.putIfAbsent(cacheKey,
                                        valuesMap = new ConcurrentHashMap<>());
                  if (oldValuesMap != null) {
                      valuesMap = oldValuesMap;
                  }
              }
              Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
              Supplier<V> supplier = valuesMap.get(subKey);
              Factory factory = null;

              while (true) {
                  if (supplier != null) {
                      //supplier可能是Factory实例或CacheValue的实例
                      //Factory.get()调用ProxyClassFactory创建value
                      //CacheValue.get()调用了Reference.get()返回缓存中的value
                      V value = supplier.get();

                      if (value != null) {
                          return value;
                      }
                  }
                  // 懒加载
                  if (factory == null) {
                      factory = new Factory(key, parameter, subKey, valuesMap);
                  }

                  //CAS存入工厂
                  if (supplier == null) {
                      supplier = valuesMap.putIfAbsent(subKey, factory);
                      if (supplier == null) {
                          supplier = factory;
                      }
                  } else {
                      if (valuesMap.replace(subKey, supplier, factory)) {
                          supplier = factory;
                      } else {
                          supplier = valuesMap.get(subKey);
                      }
                  }
              }
  }

Factory可以理解为包装工厂。

  private final class Factory implements Supplier<V> {     
  	public synchronized V get() {
              //双重检查
              Supplier<V> supplier = valuesMap.get(subKey);
          	// 是否被其他线程修改
              if (supplier != this) {
                  return null;
              }
              V value = null;
              try {
                  //ProxyClassFactory提供Class实例
                  value = Objects.requireNonNull(valueFactory.apply(key, parameter));
              } finally {
                  if (value == null) { 
                      valuesMap.remove(subKey, this);
                  }
              }

              assert value != null;

              CacheValue<V> cacheValue = new CacheValue<>(value);

          	// 到了这里表示Factory的任务已经完成,这时候二级缓存的value一定要替换为cacheValue
              if (valuesMap.replace(subKey, this, cacheValue)) {
                  //将cacheValue标记为有效缓存
                  reverseMap.put(cacheValue, Boolean.TRUE);
              } else {
                  throw new AssertionError("Should not reach here");
              }

              return value;
          }
      }
  }

ProxyClassFactory是Proxy的内部类,生产真实Class对象。

    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {

        private static final String proxyClassNamePrefix = "$Proxy";


        //唯一标记代理类
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {

                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }

                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }

                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;


            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {

                //proxyPkg = com.sun.proxy.
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }


            // 原子操作
            long num = nextUniqueNumber.getAndIncrement();
            //proxyName = com.sun.proxy.$Proxy0
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {

                throw new IllegalArgumentException(e.toString());
            }
        }
    }

ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags)最终生成代理类对象。

该方法生成的字节码类比如下

  import agent.dynamic_agent_JDK.Message;
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  import java.lang.reflect.Proxy;
  import java.lang.reflect.UndeclaredThrowableException;

  public final class ProxyMessage extends Proxy implements Message {
      private static Method m1;
      private static Method m3;
      private static Method m2;
      private static Method m0;

      public ProxyMessage(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);
          }
      }

      /*
       * 代理对象调用sendMsg(),再进一步通过反射执行传入的InvocationHandler对象中的invoke()
       *
       */
      public final void sendMsg() throws  { 
          try {
              super.h.invoke(this, m3, (Object[])null);
          } catch (RuntimeException | Error var2) {
              throw var2;
          } catch (Throwable var3) {
              throw new UndeclaredThrowableException(var3);
          }
      }

      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 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"));
              m3 = Class.forName("agent.dynamic_agent_JDK.Message").getMethod("sendMsg");
              m2 = Class.forName("java.lang.Object").getMethod("toString");
              m0 = Class.forName("java.lang.Object").getMethod("hashCode");
          } catch (NoSuchMethodException var2) {
              throw new NoSuchMethodError(var2.getMessage());
          } catch (ClassNotFoundException var3) {
              throw new NoClassDefFoundError(var3.getMessage());
          }
      }
  }

总结:

JDK动态代理使用二级缓存存放代理类,以减少代理类的重复构建以及快速获取代理类。由类加载器进一步包装成的cacheKey作为一级缓存的索引,cacheKey是弱引用实例,用来描述可用但不必要的对象,这些对象在内存溢出之前可被标记第二次垃圾回收。描述的对象被回收,cacheKey就会加入到引用队列中,在请求创建class对象前都会通过引用队列清除过期的缓存。由接口包装的Key作为二级缓存的索引,由class对象包装的CacheValue作为二级缓存的值,在cacheValue的创建过程通过双端检索机制保证线程安全问题。

posted @ 2021-09-24 08:32  活有梦想与追求  阅读(291)  评论(0)    收藏  举报