手写实现RPC框架(不带注册中心和带注册中心两种)
实现自己的RPC框架如果不需要自定义协议的话那就要基于Socket+序列化。
ProcessorHandler:
主要是用来处理客户端的请求。
package dgb.nospring.myrpc; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.Socket; /** * 任务处理类 * * @author Dongguabai * @date 2018/11/1 16:10 */ public class ProcessorHandler implements Runnable { private Socket socket; /** * 服务端发布的服务 */ private Object service; public ProcessorHandler(Socket socket, Object service) { this.socket = socket; this.service = service; } //处理请求 @Override public void run() { ObjectInputStream objectInputStream = null; try { objectInputStream = new ObjectInputStream(socket.getInputStream()); //反序列化 RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject(); Object result = invoke(rpcRequest); //将结果返回给客户端 ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeObject(result); objectOutputStream.flush(); objectInputStream.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (objectInputStream != null) { try { objectInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 反射调用 * * @param rpcRequest */ private Object invoke(RpcRequest rpcRequest) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { System.out.println("服务端开始调用------"); Object[] parameters = rpcRequest.getParameters(); Class[] parameterTypes = new Class[parameters.length]; for (int i = 0, length = parameters.length; i < length; i++) { parameterTypes[i] = parameters[i].getClass(); } Method method = service.getClass().getMethod(rpcRequest.getMethodName(), parameterTypes); return method.invoke(service, parameters); } }
RemoteInvocationHandler:
动态代理InvocationHandler。
package dgb.nospring.myrpc; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @author Dongguabai * @date 2018/11/1 16:20 */ public class RemoteInvocationHandler implements InvocationHandler{ private String host; private int port; /** *发起客户端和服务端的远程调用。调用客户端的信息进行传输 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { RpcRequest rpcRequest = new RpcRequest(); rpcRequest.setClassName(method.getDeclaringClass().getName()); rpcRequest.setMethodName(method.getName()); rpcRequest.setParameters(args); TcpTransport tcpTransport = new TcpTransport(host,port); return tcpTransport.send(rpcRequest); } public RemoteInvocationHandler(String host, int port) { this.host = host; this.port = port; } } RpcClientProxy: 客户端获取代理对象。 package dgb.nospring.myrpc; import java.lang.reflect.Proxy; /** * 客户端代理 * @author Dongguabai * @date 2018/11/1 16:18 */ public class RpcClientProxy { public <T> T clientProxy(final Class<T> interfaceClass,final String host,final int port){ return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class[]{interfaceClass},new RemoteInvocationHandler(host, port)); } }
RpcRequest:
封装的一个传输对象。
package dgb.nospring.myrpc; import java.io.Serializable; /** * 统一传输对象(让服务端知道当前要做什么) * * @author Dongguabai * @date 2018/11/1 16:16 */ public class RpcRequest implements Serializable { private String className; private String methodName; private Object[] parameters; public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public Object[] getParameters() { return parameters; } public void setParameters(Object[] parameters) { this.parameters = parameters; } }
RpcServer:
服务端发布服务。
package dgb.nospring.myrpc; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @author Dongguabai * @date 2018/11/1 15:53 */ public class RpcServer { //不建议通过Executors创建线程池,这里为了方便 private static final ExecutorService executor = Executors.newCachedThreadPool(); public void publisher(final Object service, int port) { //启动一个服务监听 try (ServerSocket serverSocket = new ServerSocket(port)) { while (true){ //通过ServerSocket获取请求 Socket socket = serverSocket.accept(); executor.execute(new ProcessorHandler(socket,service)); } } catch (IOException e) { e.printStackTrace(); } } }
TcpTransport:
处理Socket传输。
package dgb.nospring.myrpc; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; /** * socket传输 * * @author Dongguabai * @date 2018/11/1 16:25 */ public class TcpTransport { private String host; private int port; public TcpTransport(String host, int port) { this.host = host; this.port = port; } private Socket newSocket() { System.out.println("准备创建Socket连接,host:" + host + ",port:" + port); try { Socket socket = new Socket(host, port); return socket; } catch (IOException e) { throw new RuntimeException("Socket连接创建失败!host:" + host + ",port:" + port); } } public Object send(RpcRequest rpcRequest) { Socket socket = null; try { socket = newSocket(); try { ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream()); outputStream.writeObject(rpcRequest); outputStream.flush(); ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream()); Object result = inputStream.readObject(); inputStream.close(); outputStream.close(); return result; } catch (IOException | ClassNotFoundException e) { throw new RuntimeException("发起远程调用异常!",e); } } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
测试Demo
接口:
package dgb.nospring.myrpc.demo; /** * @author Dongguabai * @date 2018/11/1 15:50 */ public interface IHelloService { String sayHello(String name); } 实现类: package dgb.nospring.myrpc.demo; /** * @author Dongguabai * @date 2018/11/1 15:51 */ public class HelloServiceImpl implements IHelloService { @Override public String sayHello(String name) { return "你好," + name; } }
客户端:
package dgb.nospring.myrpc.demo; import dgb.nospring.myrpc.RpcClientProxy; /** * @author Dongguabai * @date 2018/11/1 18:10 */ public class ClientDemo { public static void main(String[] args) { RpcClientProxy proxy = new RpcClientProxy(); IHelloService helloService = proxy.clientProxy(IHelloService.class, "127.0.0.1", 12345); String name = helloService.sayHello("张三"); System.out.println(name); } }
服务端:
package dgb.nospring.myrpc.demo; import dgb.nospring.myrpc.RpcServer; /** * @author Dongguabai * @date 2018/11/1 18:07 */ public class ServerDemo { public static void main(String[] args) { RpcServer rpcServer = new RpcServer(); rpcServer.publisher(new HelloServiceImpl(),12345); } }
目前大部分远程调用框架都是基于netty去实现的,毕竟Socket的性能实在不行。
作者:Dongguabai
来源:CSDN
原文:https://blog.csdn.net/Dongguabai/article/details/83624822
------------------------------------------------------------------------------------------------------------------------
基于以上完成的RPC框架进行改造,增加基于Curator实现的ZK注册中心。
项目源码地址:https://gitee.com/white_melon_white/rpcDemo
可能这个图不太准确,但是大体意思就是服务端在注册中心中注册服务,客户端在注册中心获取服务地址进行调用,中间可能还会有一些LB等:
定义一个注册服务的顶层接口IRegistryCenter:
package dgb.nospring.myrpc.registry; /** * 注册中心顶层接口 * @author Dongguabai * @date 2018/11/1 19:05 */ public interface IRegistryCenter { /** * 注册服务 * @param serviceName 服务名称 * @param serviceAddress 服务地址 */ void register(String serviceName,String serviceAddress); }
实现类RegistryCenterImpl:
package dgb.nospring.myrpc.registry; import lombok.extern.slf4j.Slf4j; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.zookeeper.CreateMode; /** * 注册中心实现 * * @author Dongguabai * @date 2018/11/1 19:10 */ @Slf4j public class RegistryCenterImpl implements IRegistryCenter { private CuratorFramework curatorFramework; { curatorFramework = CuratorFrameworkFactory.builder() .connectString(RegistryCenterConfig.CONNECTING_STR) .sessionTimeoutMs(RegistryCenterConfig.SESSION_TIMEOUT) .retryPolicy(new ExponentialBackoffRetry(1000, 10)).build(); curatorFramework.start(); } //注册相应服务 @Override public void register(String serviceName, String serviceAddress) { String serviceNodePath = RegistryCenterConfig.NAMESPACE + "/" + serviceName; try { //如果serviceNodePath(/rpcNode/userService)不存在就创建 if (curatorFramework.checkExists().forPath(serviceNodePath)==null){ //持久化节点 curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(serviceNodePath,RegistryCenterConfig.DEFAULT_VALUE); } //注册的服务的节点路径 String addressPath = serviceNodePath+"/"+serviceAddress; //临时节点 String rsNode = curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(addressPath, RegistryCenterConfig.DEFAULT_VALUE); log.info("服务注册成功:{}",rsNode); } catch (Exception e) { throw new RuntimeException("注册服务出现异常!",e); } } }
注册中心的一些配置参数RegistryCenterConfig:
package dgb.nospring.myrpc.registry; /** * @author Dongguabai * @date 2018/11/1 19:13 */ public interface RegistryCenterConfig { /** * ZK地址int */ String CONNECTING_STR = "192.168.220.136,192.168.220.137"; int SESSION_TIMEOUT = 4000; /** * 注册中心namespace */ String NAMESPACE = "/rpcNode"; /** * value一般来说作用不大;一般主要是利用节点特性搞点事情 */ byte[] DEFAULT_VALUE = "0".getBytes(); }
为了方便,增加了一个服务发布的注解RpcAnnotation,在接口的实现类上标明这个注解表示对外发布这个接口:
package dgb.nospring.myrpc.registry; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author Dongguabai * @date 2018/11/2 8:54 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface RpcAnnotation { /** * 对外发布服务的接口 * * @return */ Class<?> value(); /** * 版本,用来区分不同版本 * @return */ String version() default ""; }
这个版本号的作用在本次Demo中没有体现出来,不过其实使用也是很简单的,可以将版本号与ZK node地址中的serviceName拼接或者绑定起来,然后根据版本号+serviceName获取相应的服务调用地址。那么客户端在发现服务的时候也要传入相应的版本进去。
首先改造服务端,服务端要将服务发布到注册中心,RpcServer:
package dgb.nospring.myrpc; import dgb.nospring.myrpc.registry.IRegistryCenter; import dgb.nospring.myrpc.registry.RpcAnnotation; import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @author Dongguabai * @date 2018/11/1 15:53 */ @Slf4j public class RpcServer { /** * 注册中心 */ private IRegistryCenter registryCenter; /** * 服务的发布地址 */ private String addressService; /** * 服务名称和服务对象之间的关系 */ private static final Map<String,Object> HANDLER_MAPPING = new HashMap<>(); //不建议通过Executors创建线程池,这里为了方便 private static final ExecutorService executor = Executors.newCachedThreadPool(); /*public void publisher(final Object service, int port) { //启动一个服务监听 try (ServerSocket serverSocket = new ServerSocket(port)) { while (true){ //通过ServerSocket获取请求 Socket socket = serverSocket.accept(); executor.execute(new ProcessorHandler(socket,service)); } } catch (IOException e) { e.printStackTrace(); } }*/ /** * 改造后的发布服务的方法 */ public void publisher() { //启动一个服务监听 //获取端口 int port = Integer.parseInt(addressService.split(":")[1]); try (ServerSocket serverSocket = new ServerSocket(port)) { //循环获取所有的接口Name HANDLER_MAPPING.keySet().forEach(interfaceName->{ registryCenter.register(interfaceName,addressService); log.info("注册服务成功:【serviceName:{},address:{}】",interfaceName,addressService); }); while (true){ //通过ServerSocket获取请求 Socket socket = serverSocket.accept(); executor.execute(new ProcessorHandler(socket,HANDLER_MAPPING)); } } catch (IOException e) { e.printStackTrace(); } } /** * 绑定服务名称和服务对象 * @param services */ public void bind(Object... services){ for (Object service : services) { //获取发布的服务接口 RpcAnnotation rpcAnnotation = service.getClass().getAnnotation(RpcAnnotation.class); if (rpcAnnotation==null){ continue; } //发布接口的class String serviceName = rpcAnnotation.value().getName(); //将serviceName和service进行绑定 HANDLER_MAPPING.put(serviceName,service); } } public RpcServer(IRegistryCenter registryCenter, String addressService) { this.registryCenter = registryCenter; this.addressService = addressService; } }
改造任务处理类ProcessorHandler:
package dgb.nospring.myrpc; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.Socket; import java.util.Map; /** * 任务处理类 * * @author Dongguabai * @date 2018/11/1 16:10 */ public class ProcessorHandler implements Runnable { private Socket socket; /** * 服务端发布的服务 */ private Map<String,Object> handlerMap; /** * 通过构造传入Map * @param socket * @param handlerMap */ public ProcessorHandler(Socket socket, Map<String, Object> handlerMap) { this.socket = socket; this.handlerMap = handlerMap; } //处理请求 @Override public void run() { ObjectInputStream objectInputStream = null; try { objectInputStream = new ObjectInputStream(socket.getInputStream()); //反序列化 RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject(); Object result = invoke(rpcRequest); //将结果返回给客户端 ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeObject(result); objectOutputStream.flush(); objectInputStream.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (objectInputStream != null) { try { objectInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 反射调用 * * @param rpcRequest */ /*private Object invoke(RpcRequest rpcRequest) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { System.out.println("服务端开始调用------"); Object[] parameters = rpcRequest.getParameters(); Class[] parameterTypes = new Class[parameters.length]; for (int i = 0, length = parameters.length; i < length; i++) { parameterTypes[i] = parameters[i].getClass(); } Method method = service.getClass().getMethod(rpcRequest.getMethodName(), parameterTypes); return method.invoke(service, parameters); }*/ /** * 反射调用(之前通过Service进行反射调用,现在通过Map获取service) * * @param rpcRequest */ private Object invoke(RpcRequest rpcRequest) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { System.out.println("服务端开始调用------"); Object[] parameters = rpcRequest.getParameters(); Class[] parameterTypes = new Class[parameters.length]; for (int i = 0, length = parameters.length; i < length; i++) { parameterTypes[i] = parameters[i].getClass(); } //从Map中获得Service(根据客户端请求的ServiceName,获得相应的服务),依旧是通过反射发起调用 Object service = handlerMap.get(rpcRequest.getClassName()); Method method = service.getClass().getMethod(rpcRequest.getMethodName(), parameterTypes); return method.invoke(service, parameters); } }
测试服务发布Demo:
package dgb.nospring.myrpc.demo; import dgb.nospring.myrpc.RpcServer; import dgb.nospring.myrpc.registry.IRegistryCenter; import dgb.nospring.myrpc.registry.RegistryCenterImpl; /** * @author Dongguabai * @date 2018/11/1 18:07 */ public class ServerDemo { public static void main(String[] args) { //之前发布服务 /* RpcServer rpcServer = new RpcServer(); rpcServer.publisher(new HelloServiceImpl(),12345); */ //改造后 IRegistryCenter registryCenter = new RegistryCenterImpl(); //这里为了方便,获取ip地址就直接写了 RpcServer rpcServer = new RpcServer(registryCenter,"127.0.0.1:12345"); //绑定服务 rpcServer.bind(new HelloServiceImpl()); rpcServer.publisher(); } }
运行结果:
在ZK客户端:
服务客户发布后,现在要解决的就是服务发现的问题。
定义一个顶层服务发现接口IServiceDiscovery:
package dgb.nospring.myrpc.registry; /** * @author Dongguabai * @date 2018/11/2 9:55 */ public interface IServiceDiscovery { /** * 根据接口名称发现服务调用地址 * @param serviceName * @return */ String discover(String serviceName); }
实现类:
package dgb.nospring.myrpc.registry; import dgb.nospring.myrpc.registry.loadbalance.LoadBalance; import dgb.nospring.myrpc.registry.loadbalance.RandomLoadBanalce; import lombok.extern.slf4j.Slf4j; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.cache.PathChildrenCache; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener; import org.apache.curator.retry.ExponentialBackoffRetry; import java.util.List; /** * 服务发现实现类 * @author Dongguabai * @date 2018/11/2 9:56 */ @Slf4j public class ServiceDiscoveryImpl implements IServiceDiscovery { /** * /rpcNode/dgb.nospring.myrpc.demo.IHelloService * 当前服务下所有的协议地址 */ private List<String> repos; /** * ZK地址 */ private String zkAddress; private CuratorFramework curatorFramework; @Override public String discover(String serviceName) { //获取/rpcNode/dgb.nospring.myrpc.demo.IHelloService下所有协议地址 String nodePath = RegistryCenterConfig.NAMESPACE+"/"+serviceName; try { repos = curatorFramework.getChildren().forPath(nodePath); } catch (Exception e) { throw new RuntimeException("服务发现获取子节点异常!",e); } //动态发现服务节点变化,需要注册监听 registerWatcher(nodePath); //这里为了方便,直接使用随机负载 LoadBalance loadBalance = new RandomLoadBanalce(); return loadBalance.selectHost(repos); } /** * 监听节点变化,给repos重新赋值 * @param path */ private void registerWatcher(String path){ PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework,path,true); PathChildrenCacheListener pathChildrenCacheListener = new PathChildrenCacheListener() { @Override public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception { repos = curatorFramework.getChildren().forPath(path); } }; pathChildrenCache.getListenable().addListener(pathChildrenCacheListener); try { pathChildrenCache.start(); } catch (Exception e) { throw new RuntimeException("监听节点变化异常!",e); } } public ServiceDiscoveryImpl(String zkAddress) { this.zkAddress = zkAddress; curatorFramework = CuratorFrameworkFactory.builder() .connectString(RegistryCenterConfig.CONNECTING_STR) .sessionTimeoutMs(RegistryCenterConfig.SESSION_TIMEOUT) .retryPolicy(new ExponentialBackoffRetry(1000, 10)).build(); curatorFramework.start(); } }
还有一套负载算法(这里简单实现了一个随机负载):
package dgb.nospring.myrpc.registry.loadbalance; import java.util.List; /** * 负载顶层接口 * @author Dongguabai * @date 2018/11/2 10:11 */ public interface LoadBalance { String selectHost(List<String> repos); } package dgb.nospring.myrpc.registry.loadbalance; import org.apache.commons.collections.CollectionUtils; import java.util.List; /** * @author Dongguabai * @date 2018/11/2 10:15 */ public abstract class AbstractLoadBanance implements LoadBalance{ /** * 通过模板方法,做一些牵制操作 * @param repos * @return */ @Override public String selectHost(List<String> repos) { if(CollectionUtils.isEmpty(repos)){ return null; } if(repos.size()==1){ return repos.get(0); } return doSelect(repos); } /** * 实现具体的实现负载算法 * @param repos * @return */ protected abstract String doSelect(List<String> repos); } package dgb.nospring.myrpc.registry.loadbalance; import java.util.List; import java.util.Random; /** * 随机负载算法 * @author Dongguabai * @date 2018/11/2 10:17 */ public class RandomLoadBanalce extends AbstractLoadBanance{ @Override protected String doSelect(List<String> repos) { return repos.get(new Random().nextInt(repos.size())); } } 还有获取服务的RpcClientProxy需要进行改造,其实就是改了一个参数传递而已: package dgb.nospring.myrpc; import dgb.nospring.myrpc.registry.IServiceDiscovery; import java.lang.reflect.Proxy; /** * 客户端代理 * @author Dongguabai * @date 2018/11/1 16:18 */ public class RpcClientProxy { private IServiceDiscovery serviceDiscovery; /* public <T> T clientProxy(final Class<T> interfaceClass,final String host,final int port){ return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class[]{interfaceClass},new RemoteInvocationHandler(host, port)); }*/ public <T> T clientProxy(final Class<T> interfaceClass){ return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class[]{interfaceClass},new RemoteInvocationHandler(serviceDiscovery)); } public RpcClientProxy(IServiceDiscovery serviceDiscovery) { this.serviceDiscovery = serviceDiscovery; } }
同样的,动态代理的InvocationHandler也要修改:
package dgb.nospring.myrpc; import dgb.nospring.myrpc.registry.IServiceDiscovery; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @author Dongguabai * @date 2018/11/1 16:20 */ public class RemoteInvocationHandler implements InvocationHandler{ private IServiceDiscovery serviceDiscovery; /** *发起客户端和服务端的远程调用。调用客户端的信息进行传输 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { RpcRequest rpcRequest = new RpcRequest(); rpcRequest.setClassName(method.getDeclaringClass().getName()); rpcRequest.setMethodName(method.getName()); rpcRequest.setParameters(args); //从ZK中获取地址 127.0.0.1:12345 String discover = serviceDiscovery.discover(rpcRequest.getClassName()); TcpTransport tcpTransport = new TcpTransport(discover); return tcpTransport.send(rpcRequest); } public RemoteInvocationHandler(IServiceDiscovery serviceDiscovery) { this.serviceDiscovery = serviceDiscovery; } }
同样的。TCPTransport也要进行改造:
package dgb.nospring.myrpc; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; /** * socket传输 * * @author Dongguabai * @date 2018/11/1 16:25 */ public class TcpTransport { private String serviceAddress; private Socket newSocket() { System.out.println("准备创建Socket连接,"+serviceAddress); String[] split = serviceAddress.split(":"); try { Socket socket = new Socket(split[0], Integer.parseInt(split[1])); return socket; } catch (IOException e) { throw new RuntimeException("Socket连接创建失败!" + serviceAddress); } } public TcpTransport(String serviceAddress) { this.serviceAddress = serviceAddress; } public Object send(RpcRequest rpcRequest) { Socket socket = null; try { socket = newSocket(); try { ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream()); outputStream.writeObject(rpcRequest); outputStream.flush(); ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream()); Object result = inputStream.readObject(); inputStream.close(); outputStream.close(); return result; } catch (IOException | ClassNotFoundException e) { throw new RuntimeException("发起远程调用异常!",e); } } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
客户端Demo:
package dgb.nospring.myrpc.demo; import dgb.nospring.myrpc.RpcClientProxy; import dgb.nospring.myrpc.registry.IServiceDiscovery; import dgb.nospring.myrpc.registry.RegistryCenterConfig; import dgb.nospring.myrpc.registry.ServiceDiscoveryImpl; /** * @author Dongguabai * @date 2018/11/1 18:10 */ public class ClientDemo { public static void main(String[] args) { /*RpcClientProxy proxy = new RpcClientProxy(); IHelloService helloService = proxy.clientProxy(IHelloService.class, "127.0.0.1", 12345); String name = helloService.sayHello("张三"); System.out.println(name);*/ IServiceDiscovery serviceDiscovery = new ServiceDiscoveryImpl(RegistryCenterConfig.CONNECTING_STR); RpcClientProxy proxy = new RpcClientProxy(serviceDiscovery); IHelloService service = proxy.clientProxy(IHelloService.class); System.out.println(service.sayHello("张三")); } }
控制台输出:
如果需要验证集群环境下,我们可以创建两个ServerDemo:
两个服务均注册到注册中心:
客户端调用还是不变:
连续调用两次客户端:
---------------------
作者:Dongguabai
来源:CSDN
原文:https://blog.csdn.net/dongguabai/article/details/83625362