说道代理大家应该都很熟悉,在日常生活中也有很多例子,比如当我们无法对真实目标无法直接访问时,需要一个代理替代我们去做这些事情,比如国内如果要访问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()的时候,输出的是改变之后的值