参考博客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给出以下笔记: