利用代理可以在运行时创建实现了一组给定接口的新类。只有 在编译时期无法确定需要实现哪个接口时才有必要使用代理 。
一、何时使用代理【资料获取】
场景: 假设你想要构造一个类的对象,这个类实现了一个或多个接口,但是在编译时你可能并不知道这些接口到底是什么。
尝试: 要想构造一个具体的类,只需要使用 newlnstance 方法或使用反射找出这个类的构造器。但是,不能实例化接口,需要在运行的程序中定义一个新类。
方式1: 为了解决这个问题, 有些程序会生成代码;将这些代码放置在一个文件中;调用编译器;然后再加载得到的类文件。很自然地, 这样做的速度会比较慢,并且需要将编译器与程序放在一起。
使用代理方式: 代理类可以在运行时创建全新的类。这样的代理类能够实现你指定的接口。
1.1、代理类包含的方法
指定接口所需要的全部方法。
Object 类中的全部方法,例如,toString、equals等。
不过,不能在运行时为这些方法定义新代码。
1.2、调用处理器
在Java中使用代理,必须要为代理提供一个【调用处理器】。调用处理器是实现了 InvocationHandler 接口的类对象。在这个接口中只有一个方法:
Object invoke(Object proxy, Method method, Object[] args)
无论何时调用代理对象的方法,调用处理器的 invoke 方法都会被调用,并向其传递Method 对象和原始的调用参数。之后调用处理器必须确定如何处理这个调用。
二、创建代理对象
要想创建一个代理对象, 需要使用 Proxy 类的 newProxylnstance 方法。 这个方法有三个参数:
一个类加载器class loader。
一个 Class 对象数组,每个元素对应需要实现的接口。
一个调用处理器。
处理完上面的事情,我们需要考虑两个问题:
1、如何定义调用处理器?
2、得到了代理对象,它能够做些什么?
这两个问题的答案,取决于我们想要用代理机制解决什么样的问题。
2.1、明确一个问题:调试、跟踪方法的调用
TraceHandler.java
public class TraceHandler implements InvocationHandler {
private Object target;
public TraceHandler(Object target) {
this.target = target;
}
// 打印所调用方法的名称和参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print(target);
System.out.print("." + method.getName()