说道代理大家应该都很熟悉,在日常生活中也有很多例子,比如当我们无法对真实目标无法直接访问时,需要一个代理替代我们去做这些事情,比如国内如果要访问google网站,一般就需要翻墙了,这就是一种代理模式。
Java中分为静态代理和动态代理模式,静态代理比较简单,在编译期就直接定义好代理类,有代理对象去访问真正对象,本文主要就讲讲动态代理,其实之前一篇Hook文章有大概说了下动态代理,有兴趣的可以看下这篇Hook文章
Activity不用注册?那就来Hook吧 ,今天详细说明下动态代理中的细节地方。
抽象对象接口,面对接口编程,抽象出定义方法,定义两个方法
/**
* @FileName: com.example.hik.lib.proxy
* @Anthor: taolin
*/
public interface ISubject {
void setInfo(int age,String name);
void sayHello();
}
复制代码
具体对象,实现接口方法:
/**
* @FileName: com.example.hik.lib.proxy
* @Anthor: taolin
*/
public class RealSubject implements ISubject{
private int age;
private String name;
@Override
public void setInfo(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public void sayHello() {
System.out.println("i'm "+name+" age "+age);
}
}
复制代码
也很明了,实现方法,实现自己逻辑,一个作为赋值操作,一个把赋值给打印出来。
接着来,定义一个类,实现InvocationHandler
/**
* @FileName: com.example.hik.lib.proxy
* @Anthor: taolin
*/
public class HookHandler implements InvocationHandler {
//真实对象,这里代表是realSubject
private Object mObject;
public HookHandler(Object mObject) {
this.mObject = mObject;
}
@Override
public Object invoke(Object mO, Method mMethod, Object[] mObjects) throws Throwable {
if (mMethod.getName().startsWith("setInfo")){
for (int i = 0; i < mObjects.length; i++) {
if (mObjects[i] instanceof Integer){
int age = (int) mObjects[i];
System.out.println("get age :"+age);
age = 20;
mObjects[i] = age;
}else if (mObjects[i] instanceof String){
String name = (String) mObjects[i];
System.out.println("get name :"+name);
name = "lisi";
mObjects[i] = name;
}
}
}
return mMethod.invoke(mObject,mObjects);
}
}
复制代码
主要看invoke这个方法,三个参数
具体实现逻辑,当代理对象拦截到setInfo()方法时,我们拿到其中的参数,进行修改,再赋值回去,最终通过 mMethod.invoke(mObject,mObjects)调用原有方法 。
主代码
public class MainClass {
public static void main(String[] args) {
//生成真实对象
ISubject subject = new RealSubject();
//生成一个方法委托类对象
HookHandler hookHandler = new HookHandler(subject);
//生成代理对象,传递进去实现HookHandler对象
ISubject proxy = (ISubject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), hookHandler);
//这里实质就是代理对象调用的方法
proxy.setInfo(10,"zhangsan");
proxy.sayHello();
}
}
复制代码
我们主要看看其中的一个方法Proxy.newProxyInstance(),三个参数
我们Run一下,看看输出
get age :10 get name :zhangsan i'm lisi age 20 Process finished with exit code 0 复制代码
可以看到,我们在invoke方法中,拦截到了setInfo方法中参数,改变之后,再赋值回去,所以,我们在调用proxy.sayHello()的时候,输出的是改变之后的值