Android 插件化——Java动态代理

最近本着不求甚解的态度重温了一下主流框架的源码,加上之前的笔记,所以趁热打铁的总结一下,学习框架或开发框架所必备的基础知识:

  • Java反射
  • Java注解
  • 注解代码自动生成
  • Java动态代理
  • AOP

1、简介

  • 代理的理解:代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法
  • 适应场景
  1. 设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,那么这时我们就可以通过代理对类进行增强
  2. 在使用和开发框架时,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现,如Retrofit
  3. Spring的AOP机制就是采用动态代理的机制来实现切面编程
  • 动态代理:在运行期动态创建代理类

以上是对动态代理的简单介绍,对于AOP使用代理机制会在下一篇文章中进行详细介绍,本文主要将最基本的Java动态代理的实现

2、实现动态代理

  • 动态代理实现AOP需要4个角色:
  1. 被代理类的接口
  2. 被代理的类:即AOP里所说的目标对象
  3. 织入器:使用接口反射机制生成一个代理类,在这个代理类中织入代码
  4. InvocationHandler切面:切面,包含了Advice和Pointcut

上面是动态代理的四个元素,下面一个一个介绍并实现过程。

  • 被代理类的接口

   任意定义一个接口,此接口就问要代理的接口,将需要在运行时动态干涉的方法定义在接口内

/**
* 代理的接口
*/
interface Study {
    fun studyEnglish()
    fun studyMath()
}
  • 被代理的类

实现了被代理接口的类

/**
* 实现的代理类
*/
class StudyImp : Study {
    override fun studyEnglish() {
        System.out.println("-----学习英语-----")
    }
    override fun studyMath() {
        System.out.println("-----学习数学-----")
    }
}
  • InvocationHandler切面

如果把程序和方法的执行看成从上倒下的过程,所谓的切面就是在某个高度的截面,即运行到此处就会被切断,从而执行其他的部分,类似于中途嫁接的过程,他的使用只需实现系统的InvocationHandler接口

public class StudyInvocationHasndler implements InvocationHandler {
    private Object object;

    public StudyInvocationHasndler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("studyEnglish")) {
            System.out.println("-----今天有外教-----");
        }
        if (method.getName().equals("studyMath")) {
            System.out.println("-----今天外教没来-----");
        }
        return method.invoke(object, args);
    }
}

实现了InvocationHandler接口重写了invoke(),见到这个方法名就应该知道这里用的时反射获取代理的信息(关于反射注解请看 Java 反射、注解),从方法中可以看出,当执行到这两个方法时会插入一条输出语句,然后再继续执行,是不是有一种横插已退的感觉,所以叫切面

  • 调用并配置代理类
fun main(args: Array) {

    // 需要代理的类的接口,被代理类实现的每个接口都必须定义
    val classes = arrayOf>(Study::class.java)
    // 创建 AOP的Advice 传入业务执行的逻辑
    val studyHandler = StudyInvocationHasndler(StudyImp())
    //生成代理类的字节码加载器
    val classLoader = StudyImp::class.java.classLoader
    // 织入代码并生成代理类
    val study: Study = Proxy.newProxyInstance(classLoader, classes, studyHandler) as Study

    //调用方法
    study.studyEnglish()
    study.studyMath()
}

其实上面的过程很好理解,导致如下:

  1. 创建需要代理接口的集合(告诉要代理谁)
  2. 创建实现InvocationHandler接口的实例(谁来代理)
  3. 创建被代理类的加载器(用到反射自然需要)
  4. 生成代理类(生成的结果)
  5. 调用方法执行

输出结果:

Android 插件化——Java动态代理_第1张图片

从运行结果上看,在每个方法执行前都会插入一句话,再执行本身的方法,就相当于代理人先执行,本人再执行,上面的四个元素中还有一个织入器并未介绍,之所以放到最后是因为这个类时系统生成的,最为代理实现的一个桥梁,下面看看生成的植入器:

  • 织入器
  1. 获取生成的代理类.class文件:在生成代理类的地方设置
// 修改系统的设置保存生成的代理类
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 

    2、运行程序后就会产生代理类:

      3、查看代理类

public final class $Proxy0 extends Proxy implements Study {  // 实现代理的接口
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m4;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {  // 带有InvocationHandler的构造函数
        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 void studyEnglish() throws  {  // 生成代理的方法
        try {
            super.h.invoke(this, m3, (Object[])null);  //  调用实现的InvocationHandler中的invoke()方法
        } 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 void studyMath() throws  {
        try {
            super.h.invoke(this, m4, (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("com.example.administrator.apiguide.aop.Study").getMethod("studyEnglish");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.example.administrator.apiguide.aop.Study").getMethod("studyMath");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

方法重写了studyMath()、studyEnglish()、toString()、hashCode()方法,studyMath()、studyEnglish()为实现接口方法,在其中都调用了 super.h.invoke(this, m3, (Object[])null); 实际调用实现的InvocationHandler中的invoke()方法,从实现代码的切入;

3、源码分析

  • Proxy.newProxyInstance(classLoader, classes, studyHandler)
private static final Class[] constructorParams =
    { InvocationHandler.class };

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

    final Class[] intfs = interfaces.clone();

    /*
     * 根据 ClassLoader 和 Class文件 获取代理的类
     */
    Class cl = getProxyClass0(loader, intfs);  //利用反射获取代理类

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
          // 获取带有InvocationHandler的构造函数
        final Constructor cons = cl.getConstructor(constructorParams);  
     
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {  // 判断类是否是私有的
            cons.setAccessible(true);     // 忽略私有
        }
        return cons.newInstance(new Object[]{h});  // 创建代理对象
    } catch (IllegalAccessException|InstantiationException e) {
       ...
    } 
}

执行逻辑:

  1. 首先判断InvocationHandler实现类h不能为空
  2. 获取传入的类加载器
  3. 反射获取代理类的构造函数,并忽略private
  4. 创建代理类,并传入InvocationHandler类h,此处的h就是生成代理类中调用的super.h.invoke

动态代理的到此结束了,想查看具体在框架中的使用实例可自行阅读Retrofit源码。

你可能感兴趣的:(Android高级进阶之旅)