• 手写实现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

  • 相关阅读:
    ucosii事件控制块------信号量集
    ucosii事件控制块------消息邮箱与消息队列
    C语言中续行符“”说明
    HTTP请求方法
    HTTP消息结构
    如何在Linux系统上安装字体
    LibreOffice openoffice 区别
    解决linux下不生成core dump文件
    开源图形数据库Neo4j使用 php开发
    Aria2 懒人安装教程
  • 原文地址:https://www.cnblogs.com/xiaoshen666/p/11118802.html
Copyright © 2020-2023  润新知