android动态代理学习笔记

来源:互联网 发布:sql字段前加内容 db2 编辑:程序博客网 时间:2024/06/05 18:37

参考博客1:http://android.jobbole.com/83143/

参考博客2:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html


近期在做自动化测试开发,有个功能是mock系统时间。但是我们知道只有系统进程才有permission通过SystemClock来设置系统时间:

SystemClock.setCurrentTimeMillis(Long timeMills)

另外,通过自动化测试工具 Mockito 也不能mock类SystemClock,因为它是final修饰的。所以,接下来考虑使用动态代理的方式来做,即希望可以将SystemClock这个类的getCurrentTimeMills进行篡改,让它返回指定的时间。

本次博客仅仅记录学习过程,至于mock系统时间的实现,后序更新。

静态代理:由程序员编写,在程序运行前,代理类.class已经存在。

动态代理:通过jdk提供的api编写,由反射机制自动生成。

关于静态代理,代码举例如下所示:Dog:接口;Samo:接口实现类 ;SamoProxy : 代理类。

public interface Dog {   //接口    public void run();}
public class Samo implements Dog {  //接口实现类    @Override    public void run() {        System.out.println("Samo is running !");    }}
public class SamoProxy extends Samo {   //静态代理类    private Samo samo;    public SamoProxy(Samo obj){        samo = obj;    }    @Override    public void run() {        System.out.println("before run");        samo.run();        System.out.println("afer run");    }}
public class RunTest {   //测试代码    public static void main(String[] args){        Samo samo = new Samo();        //萨摩run        samo.run();        //代理萨摩run        new SamoProxy(samo).run();    }}

以上是静态代理测试、学习过程。接下来介绍动态代理:

动态代理涉及一个关键类和一个关键接口:

关键接口:InvocationHandler,关键类:Proxy。

public interface InvocationHandler {    public Object invoke(Object proxy, Method method, Object[] args)        throws Throwable;}                                                                                                                                                   
Object proxy :被代理的类;Method method :要调用的函数 Object[] args:函数的参数。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException 
ClassLoader loader:类加载器  Class<?>[] interfaces:得到全部的接口  InvocationHandler h:得到InvocationHandler接口的子类实例 

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 

以下是几个关键类:

DSamoProxy :萨摩动态代理类 

import java.lang.reflect.*;/** * Created by Joe on 2016/10/15. */public class DSamoProxy implements java.lang.reflect.InvocationHandler {    private Object samo;    public  DSamoProxy(Object obj){        samo = obj;    }    public Object getProxy(){  //jdk提供的动态代理,只能传参 interface  ,返回的是萨摩代理!!很关键        return Proxy.newProxyInstance(samo.getClass().getClassLoader(),samo.getClass().getInterfaces(),this);    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        Object result = null;        System.out.println("before running");        result = method.invoke(samo,args);        System.out.println("after running");        return result;    }}
public class DRunTest {    public static void main(String[] args) {        DSamoProxy proxy = new DSamoProxy(new Samo());        Dog samoProxy = (Dog) proxy.getProxy();        samoProxy.run();    }}



以上的动态代理实现较为简单,但是如果要代理SDK中不是public的类,或者是@hide隐藏的类或者是@hide隐藏的方法呢?那就涉及到反射机制。接下来,参考博客1给出以下笔记:







0 0