使用字节码操作的替代代理类





4.00/5 (1投票)
本文提供了使用字节码操作的 Java Proxy 类的替代方案。
介绍
代理强制对象方法调用通过代理对象间接发生,代理对象充当被代理底层对象的替代或委托。通常,代理对象被声明为客户端对象不知道它们拥有代理对象实例。
java.lang.reflect.Proxy
类存在一些缺点
- 它大量使用了反射。
- 处理方法的代码不够清晰。
invoke
方法有时会变得臃肿。
使用代码
Proxy.newProxyInstance(Class clazz, Map<Class, Object> interfaceMap, Object... args)
clazz - 代理基础类
interfaceMap - 键是接口类,值是
- 或者 实现该接口的对象
- 或者实现相应接口且具有公共无参数构造函数的具体类(非抽象类)
基础类只是一个简单的类(至少有一个非私有构造函数)。如果方法的签名与接口中的一个方法相同,则将调用该函数,而不是实际实现中提供的函数(即 interfaceMap
中的值)。
您还可以使基础类抽象,实现接口并仅定义选定的方法。
例如,
public /*abstract*/ class Base /*implements Runnable, Callable, Comparable*/ {
//method from Callable
public Object call() throws Exception {
System.out.println("Call start");
Object o = (Proxy.<Callable> getInnerObject(this, Callable.class))
.call();
System.out.println("Call end");
return o;
}
//method from Comparable
public int compareTo(Object o) {
System.out.println("compareTo called with argument - " + o);
return 0;
}
}
上面的 compareTo
将被调用,而不是在 interfaceMap 中传递的实现
interfaceMap.put(Comparable.class, new Comparable(){
@Override
public int compareTo(Object o) {
System.out.println("This will not be called as inner object is not accessed from base class.");
return 0;
}
});
interfaceMap.put(Runnable.class, MyRunnable.class);
interfaceMap.put(Callable.class, MyCallable.class);
Runnable runnable = (Runnable)Proxy.newProxyInstance(Base.class, interfaceMap);
Thread thread = new Thread(runnable);
thread.start();
您可以使用类似以下方式访问实际实现对象(即 interfaceMap 中的值):
Callable callable = Proxy.<Callable> getInnerObject(this, Callable.class);
其中 this
是基础类的实例,而 Callable.class
是传递到 interfaceMap 中的键。
如果您希望没有人能够直接访问您的内部对象(即通过使用 Proxy.<Callable> getInnerObject
),您可以使用 newProxyInstance
的重载方法,该方法限制从基础类以外的任何其他类调用此函数。
字节码操作仅在第一次调用 newProxyInstance
时使用。