Java的动态对象代理

个人目前水平的理解,以后有不对会更正

简介

看过p审文章之后,先给动态对象代理下一个自己能理解到位的定义

就是通过代理接口实现了一个类似于php__call方法

不需要看很多的概念,容易懵圈,什么动静态,直接放弃

我们需要知道的时,如果实现了这么一个代理,当调用这个代理对象的任意方法时,都会触发什么方法就可以了

为此,我找到了一段描输,简单而直白

  • InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。

会自动触发invoke方法

代码测试

根据p神的测试案例,加点东西,方便自己理解在readObject中的调用

Part 1

创建一个类,实现InvocationHandler接口

主要功能就是,监听代理对象get方法调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
import java.util.Map;

public class ExampleInvocationHandler implements InvocationHandler {
protected Map map;
public ExampleInvocationHandler(Map map) {
this.map = map;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().compareTo("get") == 0) {
System.out.println("Map Object " + this.map);
System.out.println("Hook method: " + method.getName());
return "Hacked Object";
}
return method.invoke(this.map, args);
}
}

Part 2

创建一个类,实现代理对象的创建,并设置Map对象的键值对

并模拟(假设)触发readObject(test)方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.HashMap;
import java.lang.reflect.InvocationHandler;
import java.util.Map;
import java.lang.reflect.Proxy;

public class App {
public static void main(String[] args) throws Exception {
InvocationHandler handler = new ExampleInvocationHandler(new HashMap());
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
proxyMap.put("a", "world");
Object demo = new Demo(proxyMap);
String result = (String) ((Demo) demo).test();
System.out.println(result);
}
}

Part 3

实现一个类,假设存在readObject(test)方法

通过设置的成员属性调用get方法,完成一次模拟的readObject

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Map;

public class Demo {
private Map a;
public Demo(Map obj){
this.a = obj;
}
public Object test(){
String result = (String) this.a.get('a');
return result;
}
}

代码流程

  • 运行App中的main方法
  • 创建ExampleInvocationHandler对象的实例
  • ExampleInvocationHandler对象创建代理对象
  • 设置Map对象的键值对
  • 实例化一个Demo对象,并将成员属性a设置为代理对象
  • 调用Demo(自动触发Demo)的testreadObject)方法
  • 通过this.a.get自动触发代理对象的invoke方法

测试结果

运行结果如下

1619162500550

可以发现,对象已经被代理,且Map的键值对就是我们设置的键值对