前面我们已经实现了服务发现,这里的话我们快接近尾声了,也就是在实际中,我们所有的请求都是动态代理请求的,而不是由我们在每一个请求的时候去实际编写这些请求代码。如果实际编写很多代码的话,那么我们的工作量就非常大了,所以这里的话我们只需要实现一个代理类,当客户端需要请求的时候,我们直接把请求交给代理来实施即可。下面我们直接来演示下这个代理类,代码示例如下:
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 实现从注册中心获取所有的服务列表 编组请求消息体 发送网络请求 解组响应消息 处理响应结果。
代码大家看看即可,逻辑比较清晰简单。此时的项目示例图如下:
最后按照惯例,附上本案例的源码,登录后即可下载。










还没有评论,来说两句吧...