在Java中,如何在不修改一个类的情况下对该类特定的方法执行特殊的任务呢?
Java提供了代理类Proxy来解决这种问题. 前提条件是被代理对象必须至少实现一个接口.
Proxy提供了静态方法newProxyInstance以创建代理对象,具体方法如下:
java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
其中,第一个参数loader指定运行类的类加载器,第二个参数指定被代理的对象实现的所有接口,第三个是InvocationHandler 接口,必须实现invoke方法以对被代理对象的方法进行拦截.
下面是个使用代理的小例子.
1. 定义一个接口MyInterface, 该接口有两个未实现的方法:
public interface MyInterface {
void sayHi(String name);
boolean close();
}
2. 定义接口 MyInterface的实现类MyInterfaceImpl:
public class MyInterfaceImpl implements MyInterface {
@Override
public void sayHi(String name) {
System.out.println("hi! your name is: " + name);
System.out.println();
}
@Override
public boolean close() {
System.out.println("the method close() is running...");
return true;
}
}
3. 定义测试类,使用Proxy对被代理对象obj进行代理,拦截在obj上执行的所有方法:
public class ProxyDemo {
public static void main(String[] args) {
//创建被代理对象obj
final Object obj = new MyInterfaceImpl();
//创建代理者,代理obj
Object proxy = Proxy.newProxyInstance(
ProxyDemo.class.getClassLoader(), // 指定该测试类的类加载器
// 被代理的对象实现的所有接口,此处只有MyInterface这个接口
new Class[]{MyInterface.class},
new InvocationHandler(){//执行方法的句柄,是一个接口,只有一个方法invoke
//invoke方法拦截所有在被代理对象obj上执行的方法,包括参数
public Object invoke(Object proxy,Method method, Object[] args)
throws Throwable {
System.out.println("method's name = "+method.getName());
//拦截参数
if(null != args){
System.out.println("args[0] is : " + args[0].toString());
}else{
System.out.println("no args... ");
}
//拦截方法
if("close".equals(method.getName())){
System.out.println("********** 拦截到close方法,测试一下不执行该方法**********");
return false;
}else{
//把参数args传给obj,通过反射调用obj的method方法
return method.invoke(obj, args);
}
}
});
//将代理者强转成MyInterface,调用MyInterface定义的方法进行测试
MyInterface impl = (MyInterface)proxy;
impl.sayHi("小明");
impl.close();
}
}
运行结果:
在测试中,当执行句柄InvocationHandler的invoke方法拦截到impl的close方法时, 不执行close方法, 做到了在不修改原类MyInterfaceImpl的情况下对MyInterfaceImpl的close方法进行特殊处理, 这就是传说中的动态代理~~
当然,你也可以重新写个类继承MyInterfaceImpl,重写close方法,但是这样做会产生不少"没多大用途"的类,它们的职责只是为了修改一个方法... 而是用代理就比较灵活,体现了Java语言的动态代理机制.