前面我们已经实现了服务发现,这里的话我们快接近尾声了,也就是在实际中,我们所有的请求都是动态代理请求的,而不是由我们在每一个请求的时候去实际编写这些请求代码。如果实际编写很多代码的话,那么我们的工作量就非常大了,所以这里的话我们只需要实现一个代理类,当客户端需要请求的时候,我们直接把请求交给代理来实施即可。下面我们直接来演示下这个代理类,代码示例如下:
package org.wz.rpc.framework.proxy; import static java.lang.reflect.Proxy.newProxyInstance; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import org.wz.rpc.framework.client.NetClient; import org.wz.rpc.framework.discovery.ServiceDiscoverer; import org.wz.rpc.framework.model.ZookeeperMetadataData; import org.wz.rpc.framework.protocol.MessageProtocol; import org.wz.rpc.framework.protocol.MessageRequest; import org.wz.rpc.framework.protocol.MessageResponse; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; /** * 客户端代理工厂:用于创建远程服务代理类 封装编组请求、请求发送、编组响应等操作。 * */ @Slf4j public class ClientProxyFactory { private ServiceDiscoverer serviceDiscoverer; private Map<String, MessageProtocol> supportMessageProtocols; private NetClient netClient; private Map<Class<?>, Object> objectCache = new HashMap<>(); /** * 通过Java动态代理获取服务代理类 * * @param clazz 被代理类Class * @param <T> 泛型 * @return 服务代理类 */ @SuppressWarnings("unchecked") public <T> T getProxy(Class<T> clazz) { return (T) this.objectCache.computeIfAbsent(clazz, cls -> newProxyInstance(cls.getClassLoader(), new Class<?>[] { cls }, new ClientInvocationHandler(cls))); } public ServiceDiscoverer getServiceDiscoverer() { return serviceDiscoverer; } public void setSid(ServiceDiscoverer serviceDiscoverer) { this.serviceDiscoverer = serviceDiscoverer; } public Map<String, MessageProtocol> getSupportMessageProtocols() { return supportMessageProtocols; } public void setSupportMessageProtocols(Map<String, MessageProtocol> supportMessageProtocols) { this.supportMessageProtocols = supportMessageProtocols; } public NetClient getNetClient() { return netClient; } public void setNetClient(NetClient netClient) { this.netClient = netClient; } /** * 客户端服务代理类invoke函数细节实现 */ public class ClientInvocationHandler implements InvocationHandler { private Class<?> clazz; private Random random = new Random(); public ClientInvocationHandler(Class<?> clazz) { super(); this.clazz = clazz; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Exception { if (method.getName().equals("toString")) { return proxy.getClass().toString(); } if (method.getName().equals("hashCode")) { return 0; } // 1、获得服务信息 String serviceName = this.clazz.getName(); //和nacos一样,从注册中心去拉取对应服务的服务列表 List<ZookeeperMetadataData> services = serviceDiscoverer.getServices(serviceName); log.info("当前rpc服务:{} 从注册中心获取到的服务列表是:{}",JSON.toJSONString(services)); //需要判断下从注册中心获取到的注册列表是不是空的,如果是空的,那么需要直接抛出异常,因为调用不到 if (services == null || services.isEmpty()) { throw new RuntimeException("No provider available!"); } // 从注册中心获取到服务列表之后,需要使用负载均衡来进行调用。因此随机选择一个服务提供者(软负载均衡) ZookeeperMetadataData service = services.get(random.nextInt(services.size())); // 2、构造request对象 MessageRequest req = new MessageRequest(); req.setServiceName(service.getName()); req.setMethod(method.getName()); req.setParameterTypes(method.getParameterTypes()); req.setParameters(args); // 3、协议层编组 // 获得该方法对应的协议 MessageProtocol protocol = supportMessageProtocols.get(service.getProtocol()); // 编组请求 byte[] data = protocol.marshallingRequest(req); // 4、调用网络层发送请求 byte[] repData = netClient.sendRequest(data, service); // 5解组响应消息 MessageResponse rsp = protocol.unmarshallingResponse(repData); // 6、结果处理 if (rsp.getException() != null) { throw rsp.getException(); } return rsp.getReturnValue(); } } }
这个代理里面主要是先的有:
初始化服务发现 初始化请求协议 初始化客户端client 实现从注册中心获取所有的服务列表 编组请求消息体 发送网络请求 解组响应消息 处理响应结果。
代码大家看看即可,逻辑比较清晰简单。此时的项目示例图如下:
最后按照惯例,附上本案例的源码,登录后即可下载。
还没有评论,来说两句吧...