動態代理

目錄:

1.動態代理與靜態代理的使用區別
2.動態代理實現原理
3.動態代理的使用場景

1.靜態代理

代理模式給某一個對象提供一個代理對象,并由代理對象控制對原對象的引用。通俗的來講代理模式就是我們生活中常見的中介角色。

public interface Iinterface {
  void dosomething();
 }
public class RealMovie implements Iinterface {

    @Override
    public void dosomething() {
        System.out.println("做一些事");
    }

}

上面是具體的實現類,下面是代理類

public class ProxyA implements Iinterface {
    ProxyA mo;

    public ProxyA(ProxyA mo) {
        super();
        this.mo = mo;
    }
    @Override
    public void dosomething() {
        ganbiedeshi(true);
        mo.play();
    }

    public void ganbiedeshi(boolean isStart){
            System.out.println("做一些別的事!");
    }
}

調用時候就直接使用代理類,不直接使用實現類,里面可以做一些額外的邏輯。

2.動態代理

使用代碼入下:

  public interface  IActionInterface{
        void eat();
    }

    public static class Dog implements IActionInterface{
        @Override
        public void eat() {
            Log.e("動態代理", "eat: 狗吃肉");
        }
    }

    public void main(String[] args) {
        Dog dog = new Dog();

        IActionInterface action  = (IActionInterface) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new Class[]{IActionInterface.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Log.e("動態代理", "method:" + method.getName());
                return method.invoke(dog,args);
            }
        });
        action.eat();
    }

比起靜態代理,沒增加一個需要代理的對象都要增加代理類,而動態代理直接作用接口,在運行時候,動態創建代理類到內存數據分區中的方法區中,如果我們想看到,也可以通過下面代碼在java中生成。

 String name = IActionInterface.class.getName()+"$Proxy0"; //生成代理指定接口的Class數據
         byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{IActionInterface.class});
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("lib/" + name+".class");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            fos.write(bytes);
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

3.動態代理實現原理

根據上面的生成代碼,我們把運行時生成的類寫出來后,代碼如下:

public final class $Proxy0 extends Proxy implements IActionInterface
{
  private static Method m1;
  private static Method m2;
  private static Method m3;
  private static Method m0;
  
  /**
  *注意這里是生成代理類的構造方法,方法參數為InvocationHandler類型,看到這,是不是就有點明白
  *為何代理對象調用方法都是執行InvocationHandler中的invoke方法,而InvocationHandler又持有
  *
  */
  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }
  

  
 
  /**
  * 
  *這里調用代理對象的giveMoney方法,直接就調用了InvocationHandler中的invoke方法,并把m3傳了進去。
  *this.h.invoke(this, m3, null);這里簡單,明了。
  *來,再想想,代理對象持有一個InvocationHandler對象,InvocationHandler對象持有一個被代理的對象,
  *再聯系到InvacationHandler中的invoke方法。嗯,就是這樣。
  */
  public final void eat()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
 static
  {
    try
    {
    
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m3 = Class.forName("proxy. IActionInterface").getMethod("eat", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }

}
1.首先執行
 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
 // 1.首先使用原型設計模式,保存傳入的接口
        final Class<?>[] intfs = interfaces.clone();
        // 2.主線!!!!
        Class<?> cl = getProxyClass0(loader, intfs);
        try {
//   3.獲取到上面類 通過反射創建并返回對象
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                cons.setAccessible(true);
            }
            return cons.newInstance(new Object[]{h});
       //省略代碼
    }

可以看到就簡單的幾步,首先保存了傳入的接口,然后獲取到類,再通過反射創建類的對象并返回

2.類如何生成的
private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
//完成檢測接口數量后,調用代理緩存類中獲取
        return proxyClassCache.get(loader, interfaces);
    }
3.通過代碼proxyClassCache.get生成類

1.生成規則命名就是Proxy$0 0到N命名.生成的類繼承Proxy,實現我們要代理的接口
2.構造方法傳入了InvacationHandeler 給到super
3.默認靜態代碼塊中反射創建m1 ,m2 ....作為參數包含我們的方法和object的方法
4.具體的方法中調用this.h.invoke(this, m3, null); 也就是重寫的invoke方法

動態代理的使用場景

1.retrofit框架中調用create時候返回一個動態代理對象

public <T> T create(final Class<T> service) {
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
 
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });

————————————————
版權聲明:本文為CSDN博主「Simple_ R   」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/M_sdn/article/details/84856273

2.ASM進程通信也使用到
3.可以做一些接口執行的統計,比如耗時,當然有網絡請求攔截器

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容