现在Java这块的面试的要求真的是越来越高了,十年之后,SpringCloud,Double,K8S都有很多的要求,只是前端弱化了点,可能跟前后端分离有关系。现在去面试,不怎么考前端。

但是Java的难度真的我感觉,已经是接近要上天了,源码,原理,比较偏的冷门知识都要会。

比如关于RPC这块,涉及的就有double,openfeign等等。但是,我们不能被这些五花八门的框架,如果我们经常被这些框架带着走,很容易就陷入到学不动了的境地。

关于RPC这块,实际上是构建在动态代理的基础上,文章链接地址为:

https://www.cnblogs.com/zyl2016/p/9875593.html

以下是点评:

其实咱们仔细想想,服务端大家都懂,要不就是restful接口,要不就是像double那样提供的service(不过我不建议再用double了)。

那我们要研究的就是客户端怎么就能把远过程调用RPC注入到接口呢?然后这里就涉及到动态代理,我们看文章的下面这段代码:

package socketrpc.client;

import socketrpc.IHello;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;

public class RpcClientProxy<T> implements InvocationHandler {

    private  Class<T> serviceInterface;
    private InetSocketAddress addr;

    public RpcClientProxy(Class<T> serviceInterface, String ip,String port) {
        this.serviceInterface = serviceInterface;
        this.addr = new InetSocketAddress(ip, Integer.parseInt ( port ));
    }

    public T getClientIntance(){
        return (T) Proxy.newProxyInstance (serviceInterface.getClassLoader(),new Class<?>[]{serviceInterface},this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Socket socket = null;
        ObjectOutputStream output = null;
        ObjectInputStream input = null;

        try {
            // 2.创建Socket客户端,根据指定地址连接远程服务提供者
            socket = new Socket();
            socket.connect(addr);

            // 3.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者
            output = new ObjectOutputStream(socket.getOutputStream());
            output.writeUTF(serviceInterface.getName());
            output.writeUTF(method.getName());
            output.writeObject(method.getParameterTypes());
            output.writeObject(args);

            // 4.同步阻塞等待服务器返回应答,获取应答后返回
            input = new ObjectInputStream(socket.getInputStream());
            return input.readObject();
        } finally {
            if (socket != null) socket.close();
            if (output != null) output.close();
            if (input != null) input.close();
        }
    }

    public static void main(String[] args) {
        RpcClientProxy client = new RpcClientProxy<>(IHello.class,"localhost","6666");
        IHello hello = (IHello) client.getClientIntance ();
        System.out.println (hello.sayHello ( "socket rpc" ));
    }
}

重点是这里用到了动态代理:

        RpcClientProxy client = new RpcClientProxy<>(IHello.class,"localhost","6666");
        IHello hello = (IHello) client.getClientIntance ();

当然,在实现接口里面的方法时,作者这个例子是使用了socket,获取返回数据,这个也容易理解,为什么double服务端会有个端口20880,这个端口不就是底层socket-client获取数据的端口吗。

再给你看下feign的源码,几个地方:

在这里插入图片描述再深入看下executeAndDecode看下这个方法:

  Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
    Request request = targetRequest(template);

    if (logLevel != Logger.Level.NONE) {
      logger.logRequest(metadata.configKey(), logLevel, request);
    }

    Response response;
    long start = System.nanoTime();
    try {
      response = client.execute(request, options);
      // ensure the request is set. TODO: remove in Feign 12
      response = response.toBuilder()
          .request(request)
          .requestTemplate(template)
          .build();
    } catch (IOException e) {
      if (logLevel != Logger.Level.NONE) {
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
      }
      throw errorExecuting(request, e);
    }
    long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);


    if (decoder != null)
      return decoder.decode(response, metadata.returnType());

    CompletableFuture<Object> resultFuture = new CompletableFuture<>();
    asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
        metadata.returnType(),
        elapsedTime);

    try {
      if (!resultFuture.isDone())
        throw new IllegalStateException("Response handling not done");

      return resultFuture.join();
    } catch (CompletionException e) {
      Throwable cause = e.getCause();
      if (cause != null)
        throw cause;
      throw e;
    }
  }

看到了吗,里面用的是Request,说明用的是http的请求:
在这里插入图片描述总结一下,不管是dubble还是feign用的都是动态代理,所不同的是,double的在调用的时候用的是socket,而feign用的是http。

有了这个理解,就明白了,double为什么更能承受高并发,因为double用的是socket。而feign用的是http的通信协议,所以,feign当然用起来更方便。

更好的参考文章:https://blog.csdn.net/weixin_34066347/article/details/91631844

想要了解更多的同学们,请关注下我的公众号哟。最近忙于项目开发,加上我又不喜欢追热点,公众号粉丝一直不多,如果有你们的关注,那便是我努力的最大动力。

image

关注「动哒」

让你每天进步一点点

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐