基于netty的简易RPC框架
一、基础设计
1、服务注册和发现
rpc远程框架我们要实现的客户端使用功能是,远程调用接口的提供者producer使用@server注解,将此service注解的服务类信息,服务地址(本机ip+netty设置的服务端口),注册到注册中心上,注册中心采用zookeeper。调用接口端consumer在调用类的服务字段上使用@inject,即可调用远端producer,这个是使用服务发现类zookeeperDiscovery实现的,即在zookpeer找到对应服务名的临时节点信息,利用loadBalance进行本地轮询,返回单个服务。
服务注册代码:
public void register(ServiceObject so) throws Exception {
// 注册到本地
super.register(so);
MyService service = new MyService();
String host = InetAddress.getLocalHost().getHostAddress();
String address = host + ":" + port;
service.setAddress(address);
service.setName(so.getClazz().getName());
service.setWeight(this.weight);
this.exportService(service);
}
/**
* 暴露服务到zookeeper中
*/
private void exportService(MyService serviceResource) {
String serviceName = serviceResource.getName();
String uri = JSON.toJSONString(serviceResource);
try {
uri = URLEncoder.encode(uri, RpcConstant.UTF_8);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String servicePath = RpcConstant.ZK_SERVICE_PATH + RpcConstant.PATH_DELIMITER + serviceName + "/service";
if (!zkClient.exists(servicePath)) {
zkClient.createPersistent(servicePath, true);
}
String uriPath = servicePath + RpcConstant.PATH_DELIMITER + uri;
if (zkClient.exists(uriPath)) {
zkClient.delete(uriPath);
}
zkClient.createEphemeral(uriPath);
}
服务发现代码:
public class ZookeeperServerDiscovery implements ServerDiscovery{
private ZkClient zkClient;
public ZookeeperServerDiscovery(String zkAddress) {
zkClient = new ZkClient(zkAddress);
zkClient.setZkSerializer(new ZookeeperSerializer());
}
@Override
public List<MyService> findServiceList(String name) {
String servicePath = RpcConstant.ZK_SERVICE_PATH + RpcConstant.PATH_DELIMITER + name + "/service";
List<String> children = zkClient.getChildren(servicePath);
return Optional.ofNullable(children).orElse(new ArrayList<>()).stream().map(str -> {
String deCh = null;
try {
deCh = URLDecoder.decode(str, RpcConstant.UTF_8);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return JSON.parseObject(deCh, MyService.class);
}).collect(Collectors.toList());
}
public ZkClient getZkClient() {
return zkClient;
}
}
2、初始化启动
初始化启动采用spring的ApplicationListener<ContextRefreshedEvent>的监听器方式,即在spring启动时,就要对@service注解的bean,进行服务注册,对@inject注解的字段,基于字段类型进行创建代理类。( 代理类的功能就是基于服务发现,用netty创建一个client端,调用远程服务提供者的方法。)
public class DefaultRpcProcessor implements ApplicationListener<ContextRefreshedEvent> {
private static Logger logger = LoggerFactory.getLogger(DefaultRpcProcessor.class);
private ClientProxyFactory clientProxyFactory;
private ServerRegister serverRegister;
private RpcServer rpcServer;
public DefaultRpcProcessor(ClientProxyFactory clientProxyFactory, ServerRegister serverRegister, RpcServer rpcServer) {
this.clientProxyFactory = clientProxyFactory;
this.serverRegister = serverRegister;
this.rpcServer = rpcServer;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// Spring启动完毕过后会收到一个事件通知
if (Objects.isNull(event.getApplicationContext().getParent())){
ApplicationContext context = event.getApplicationContext();
// 开启服务
startServer(context);
// 注入Service
injectService(context);