在Java的JDK动态代理中,主要涉及两个类,一个是java.lang.reflect.Proxy,一个是java.lang.reflectInvocationHandler。要使用JDK的动态代理需要一个实现InvocationHandler接口的中间类,这个接口只有一个方法invoke()方法,对处理类的所有方法的调用都会变成对invoke()方法的调用,这样就可以在invoke()方法中添加统一的处理逻辑(也可以根据method参数判断是哪个方法)。中间类(实现了InvocationHandler的类)有一个委托类对象引用,在invoke()方法中调用了委托类对象的相应方法,通过这种聚合的方式持有委托类对象引用,把外部对invoke()方法的调用最终都转为对委托类对象的调用。
实际上,中间类与委托类构成了静态代理关系,在这个关系中,中间类是代理类,委托类是委托类。然后代理类与中间类也构成一个静态代理关系,在这个关系中,中间类是委托类,代理类是代理类。也就是说,动态代理关系是由两组静态代理关系组成的,这就是JDK动态代理的原理。
InvocationHandler接口的定义源码与参数说明(在注释中)
public interface InvocationHandler {
/**
* 调用处理
* @param proxy 代理类对象
* @param methon 标识具体调用的是代理类的哪个方法
* @param args 代理类方法的参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
定义接口和接口的实现类
// 委托类接口
public interface HelloService {
void sayHello(String userName);
void sayByeBye(String userName);
}
// 委托类
public class HelloServiceImpl implements HelloService {
public void sayHello(String userName) {
System.out.println("hello, " + userName);
}
public void sayByeBye(String userName) {
System.out.println("byebye, "+ userName);
}
}
定义一个实现InvocationHandler接口的中间类
// 中间类
public class HelloInvocationHandler implements InvocationHandler {
/**
* 中间类持有委托类对象的引用,这里会构成一种静态代理关系
*/
private Object obj;
/**
* 有参构造器,传入委托类的对象
*
* @param obj 委托类的对象
*/
public HelloInvocationHandler(Object obj) {
this.obj = obj;
}
/**
* 动态生成代理类对象,Proxy.newProxyInstance
*
* @return 返回代理类的实例
*/
public Object newProxyInstance() {
return Proxy.newProxyInstance(
// 指定代理对象的类加载器
obj.getClass().getClassLoader(),
// 代理对象需要实现的接口,可以同时指定多个接口
obj.getClass().getInterfaces(),
// 方法调用的实际处理者,代理对象的方法调用都会转发到这里
this);
}
/**
* @param proxy 代理对象
* @param method 代理方法
* @param args 方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在invoke前做一些事情
System.out.println("do something before invoke...");
// 执行invoke
Object result = method.invoke(obj, args);
// 在invoke之后做一些事情
System.out.println("do something after invoke...");
return result;
}
}
通过中间类访问委托类
// 测试动态代理类
public class HelloTest {
public static void main(String[] args) {
HelloInvocationHandler helloInvocationHandler = new HelloInvocationHandler(new HelloServiceImpl());
HelloService helloService = (HelloService) helloInvocationHandler.newProxyInstance();
helloService.sayHello("yanggb");
helloService.sayByeBye("yanggb");
}
}