android动态代理学习笔记

本文探讨了在Android环境中如何通过动态代理技术实现对不可直接修改的类进行功能扩展,特别是针对SystemClock类的模拟,以达到自动化测试中对系统时间进行模拟的目的。文中对比了静态代理与动态代理的区别,并通过示例代码展示了如何使用动态代理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值