利用代理可以在运行时创建一个实现了一组给定接口的新的实现类。
假设有一个表示接口的Class对象,它的确切类型在编译时无法知道,要想在运行时构造一个实现了该接口的类,就需要使用newInstance方法或者反射找到构造器,很复杂,很麻烦。那么代理可以解决这个问题!
代理需要提供一个实现了InvocationHandler接口的调用处理器,在这个接口中只定义了一个方法:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
- 这样无论何时调用代理对象的方法,调用处理器的invoke方法都会被调用,并向其传递Method对象和原始的参数,调用处理器必须在invoke方法中给出处理调用的方式。
创建代理对象
创建一个代理对象,需要使用Proxy类的newProxyInstance方法:
public class Proxy implements java.io.Serializable {
// more code ...
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException
// more code ...
}
- 这个方法中包含了三个参数:
- ClassLoader:指定一个类加载器,null表示使用默认的加载器;
- Class<?>[]:表示需要实现的接口数组;
- InvocationHandler:一个调用处理器。
一个例子🌰
这里举一个程序员写代码,然后公司作为代理的例子:
- 首先创建一个Programmer接口:
public interface Programmer {
void writeCode(String code);
void postProduct();
}
- 写一个Programmer实现类
public class ProgrammerImpl implements Programmer {
@Override
public void writeCode(String code) {
System.out.println("写代码。。。。。。。" + code);
}
@Override
public void postProduct() {
System.out.println("提交产品。。。。。。。");
}
}
- 写一个调用处理器
public class Handler implements InvocationHandler {
private Object target;
public Handler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我代表:" + target.getClass().getName());
System.out.println("要执行的行为是:" + method.getName());
System.out.println("传递的参数包括:");
if (args != null && args.length > 0) {
for (Object obj : args
) {
System.out.println(obj);
}
}
System.out.println("开始执行方法:");
method.invoke(target, args);
System.out.println("方法执行完毕");
return null;
}
}
- 代理主类测试
public class ProxyMain {
public static void main(String[] args) {
Programmer programmer = new ProgrammerImpl();
Handler handler = new Handler(programmer);
Programmer programmerProxy = (Programmer) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Programmer.class}, handler);
programmerProxy.writeCode("java");
programmerProxy.postProduct();
}
}
- 运行结果
我代表:com.ytuan.ProgrammerImpl
要执行的行为是:writeCode
传递的参数包括:
java
开始执行方法:
写代码。。。。。。。java
方法执行完毕
我代表:com.ytuan.ProgrammerImpl
要执行的行为是:postProduct
传递的参数包括:
开始执行方法:
提交产品。。。。。。。
方法执行完毕
代理类的特性
- 代理类都是在运行过程中创建的,一旦创建后,和常规类一样
- 所有的代理类都扩展于Proxy类
- 一个代理类只有一个实例域——InvocationHandler的实现类,InvocationHandler的invoke方法包含了处理逻辑的代码。
- 对于特定的类加载器和一组接口来说,只有一个代理类;即如果多次使用相同的类加载器和同一组接口调用newInstance方法,那么生成的代理类是一致的。
- 代理类一定public和final修饰的