RPC中远程服务调用是通过动态代理来实现的,下图形象的说明了这一过程。
系统A(服务消费端只有接口定义,并没有实现类,所以需要通过动态代理的方式,来调用系统B(服务提供端)的具体实现类的方法。动态实现类B内部其实是通过网络通信的方式来进行远程方法调用的。
JDK/CGLIB 动态代理
从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。
1 JDK动态代理
在 Java 动态代理机制中 InvocationHandler
接口和 Proxy
类是核心。
要实现动态代理的话,首先需要实现InvocationHandler
来自定义处理逻辑。 当我们的动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler
接口类的 invoke
方法来调用。
public interface InvocationHandler {
/**
* 当你使用代理对象调用方法的时候实际会调用到这个方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
invoke()
方法有下面三个参数:
- proxy :动态生成的代理类
- method : 与代理类对象调用的方法相对应
- args : 当前 method 方法的参数
然后,我们需要用Proxy
类中newProxyInstance()
这个方法来生成一个代理对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
{
......
}
这个方法一共有 3 个参数:
- loader :类加载器,用于加载代理对象。
- interfaces : 被代理类实现的一些接口;
- h : 实现了 InvocationHandler 接口的对象;
也就是说:你通过Proxy
类的newProxyInstance()
创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler
接口的类的 invoke()
方法。 你可以在invoke()
方法中自定义处理逻辑,比如在方法执行前后做什么事情.
使用实例
public interface SmsService {
String send(String message);
}
public class SmsServiceImpl implements SmsService {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
public class DebugInvocationHandler implements InvocationHandler {
/**
* 代理类中的真实对象
*/
private final Object target;
public