JDK动态代理在RPC框架中的应用
RPC框架中一般都有3个角色:服务提供者、服务消费者和注册中心。服务提供者将服务注册到注册中心,服务消费者从注册中心拉取服务的地址,并根据服务地址向服务提供者发起RPC调用。动态代理在这个RPC调用的过程中有什么作用?对于服务消费者,一般只会依赖服务接口,而服务的具体实现是在服务提供者这一端的,服务消费者和服务提供者分别部署在不同的机器上,服务消费者调用接口中的方法时怎么能够得到结果呢?JDK的动态代理就派上用场了。服务消费者使用JDK的动态代理技术,可以创建接口的代理对象,并在回调函数中将自己要调用的接口名称、方法签名信息通过http或者tcp的方式发送给服务提供者,服务提供者再通过反射的方式调用本地的服务,最后将结果通过http或tcp的方式返回给消费者。
下面是一个简单的演示程序:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 import java.util.HashMap; 5 import java.util.Map; 6 7 /** 8 * 动态代理在RPC中的使用 9 * 10 * @author syj 11 */ 12 public class JDKProxyTest { 13 14 // --------------------------- 模拟RPC客户端 --------------------------- 15 16 // 客户端依赖服务端的接口(实现类在服务端) 17 private static IUserService userService; 18 19 public static void main(String[] args) { 20 // 根据接口创建代理对象 21 userService = (IUserService) Proxy.newProxyInstance( 22 JDKProxyTest.class.getClassLoader(), 23 new Class[]{IUserService.class}, 24 new InvocationHandler() { 25 // 在回调方法模拟进行RPC调用(通过http或者tcp与服务端通信) 26 @Override 27 public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { 28 return rpcInvoke(IUserService.class.getSimpleName(), method.getName(), method.getParameterTypes(), params); 29 } 30 } 31 ); 32 // 本地调用 33 String result = userService.sayHello("hello"); 34 System.out.println(">>>> result =" + result); 35 } 36 37 38 // --------------------------- 模拟RPC服务端 --------------------------- 39 40 /** 41 * 反射调用 42 * 43 * @param methodName 方法名称 44 * @param parameterTypes 方法参数类型 45 * @param parameters 方法参数 46 * @return 47 */ 48 private static Object rpcInvoke(String interfaceName, String methodName, Class<?>[] parameterTypes, Object[] parameters) { 49 Object result = null; 50 try { 51 // 根据接口名称从Bean容器中获取Bean实例 52 Object serviceBean = beanMap.get(interfaceName); 53 // 反射调用 54 Class<?> serviceClass = serviceBean.getClass(); 55 Method method = serviceClass.getMethod(methodName, parameterTypes); 56 method.setAccessible(true); 57 // 得到调用结果 58 result = method.invoke(serviceBean, parameters); 59 } catch (Exception e) { 60 e.printStackTrace(); 61 } 62 return result; 63 } 64 65 // 模拟Bean容器, key为接口名称, value为bean实例 66 private static Map<String, Object> beanMap = new HashMap<String, Object>() {{ 67 put("IUserService", new UserServiceImpl()); 68 }}; 69 }
接口(服务提供者和服务的消费者都会依赖该接口):
1 public interface IUserService { 2 String sayHello(String content); 3 }
服务提供者实现类:
public class UserServiceImpl implements IUserService { @Override public String sayHello(String content) { return content + "::" + System.currentTimeMillis(); } }
其实,JDK的动态代理技术,不仅可以应用在RPC框架中,也可以应用在所有基于客户端和服务端通信的架构中,比如微服务架构中的注册中心、配置中心、消息中心等。