说在前面,本篇文章只讲解InvocationHandler的使用。在阅读本篇文章之前,需要了解设计模式中的代理模式。
直接贴代码,这段代码是代表Subject的IHello接口
/**
* Subject
* RealSubject和Proxy需要实现这个接口
*/
public interface IHello {
void sayHello(String name);
}
代表RealSubject的ConcreteHello类,实现了IHello接口,是实际执行操作的对象
/**
* RealSubject
* 实现IHello接口,是实际执行操作的对象
*/
public class ConcreteHello implements IHello {
@Override
public void sayHello(String name) {
System.out.println("Hello" + name);
}
}
动态代理就是Proxy的class文件在程序运行前是不存在,其字节码是在运行的时候自动生成的。在这里代理类,我们借助Proxy的newProxyInstance方法在运行时自动创建。
/**
* 实现Java自带的InvocationHandler接口,重写invoke方法来调用RealSubject的方法
* 自定义getProxy来获取代理对象。该方法通过Proxy的newProxyInstance方法来生成代理对象。
*/
public class HelloHandler implements InvocationHandler {
//持有RealSubject的引用,即持有被代理对象的引用
private IHello concreteHello;
/**
* 接收RealSubject,生成并返回Proxy对象
* @param concreteHello 被代理对象
* @return 返回动态生成的Proxy对象
*/
public Object getProxy(IHello concreteHello) {
this.concreteHello = concreteHello;
// Proxy.newProxyInstance方法用来生成目标对象的代理类
// 第一个参数是 目标对象的类加载器
// 第二个参数是 目标对象的接口列表
// 第三个参数是 InvocationHandler的实现类
return Proxy.newProxyInstance(
this.concreteHello.getClass().getClassLoader(),
this.concreteHello.getClass().getInterfaces(),
this
);
}
/**
* 调用目标对象的方法,可以在方法执行前后添加自己的操作
* @param proxy 代理对象
* @param method RealSubject对象中被Proxy调用的方法
* @param args 被Proxy调用的方法参数列表
* @return Proxy调用的方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//我们可以在方法调用之前添加自己的操作
System.out.println("before invoke");
//调用RealSubject的方法
Object result = method.invoke(this.concreteHello, args);
//我们可以在方法调用之后添加自己的操作
System.out.println("after invoke");
return result;
}
}
下面我们来测试看是不是能执行成功
public class InvocationHandlerTest {
public static void main(String[] args) {
//ConcreteSubject
IHello concreteHello = new ConcreteHello();
//辅助生成Proxy对象
HelloHandler helloHandler = new HelloHandler();
//Proxy
IHello iHello = (IHello)helloHandler.getProxy(concreteHello);
//通过Proxy调用RealSubject的sayHello方法
iHello.sayHello("Jerry");
}
}