SOFA RPC源码解析之Rest服务(3)-客户端调用

版权声明: https://blog.csdn.net/beyondself_77/article/details/80862734

1 SOFA RPC源码解析

1.1 Rest服务

1.1.1 客户端调用

        当我们在SpringXML文件中使用sofa:reference引用服务以后,我们就可以在其它类中引用创建的指定接口的代理对象,并像调用本地Java类那样,调用接口的某个方法。

        以下通过在Spring应用上下文中按照名字personReferenceRest查找com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService接口的代理对象,然后调用其sayName方法,描述客户端调用Rest服务的流程:

1.  public static void main(String[] args)throws InterruptedException {
2.       
3.        ConfigurableApplicationContext ac =SpringApplication.run(SofaBootRpcDemoApplication.class, args);
4.       
5.        PersonService personService = (PersonService)ac.getBean("personReferenceRest");
6.       
7.        personService.sayName("Mike");
8.   
9.      }

        通过ConfigurableApplicationContext类getBean方法,获取名字为personReferenceRest的实例,此时返回PersonService接口的JDK代理对象,此代理对象的handler为JDKInvocationHandler,实现了PersonService接口。

        当调用JDK代理对象的sayName方法时,实际执行的是JDKInvocationHandler的invoke方法:

1.  public Object invoke(Object proxy, Methodmethod, Object[] paramValues)
2.          throws Throwable {
3.          String methodName = method.getName();
4.          Class[] paramTypes =method.getParameterTypes();
5.          ……
6.          SofaRequest sofaRequest =MessageBuilder.buildSofaRequest(method.getDeclaringClass(),
7.              method, paramTypes, paramValues);
8.          SofaResponse response =proxyInvoker.invoke(sofaRequest);
9.          if (response.isError()) {
10.             throw new SofaRpcException(……);
11.         }
12.         Object ret = response.getAppResponse();
13.         if (ret instanceof Throwable) {
14.             throw (Throwable) ret;
15.         } else {
16.             if (ret == null) {
17.                 returnClassUtils.getDefaultArg(method.getReturnType());
18.             }
19.             return ret;
20.         }
21.     }

  JDKInvocationHandler类invoke方法主要处理逻辑如下:

  • 获取方法名和参数类型数组;
  • 调用MessageBuilder类buildSofaRequest方法,根据method信息构造SOFA RPC请求SofaRequest;
  • 以SofaRequest为参数,调用proxyInvoker(DefaultClientProxyInvoker类型)的invoke方法,发起SOFA远程服务调用:
1.  public SofaResponse invoke(SofaRequestrequest) throws SofaRpcException {
2.          SofaResponse response = null;
3.          Throwable throwable = null;
4.          try {
5.              RpcInternalContext.pushContext();
6.              RpcInternalContext context =RpcInternalContext.getContext();
7.              context.setProviderSide(false);
8.              // 包装请求
9.              decorateRequest(request);
10.             try {
11.                 // 产生开始调用事件
12.                 if(EventBus.isEnable(ClientStartInvokeEvent.class)) {
13.                     EventBus.post(newClientStartInvokeEvent(request));
14.                 }
15.                 // 得到结果
16.                 response = cluster.invoke(request);
17.             } catch (SofaRpcException e) {
18.                 throwable = e;
19.                 throw e;
20.             } finally {
21.                 // 产生调用结束事件
22.                 if(EventBus.isEnable(ClientEndInvokeEvent.class)) {
23.                     EventBus.post(newClientEndInvokeEvent(request, response, throwable));
24.                 }
25.             }
26.             // 包装响应
27.             decorateResponse(response);
28.             return response;
29.         } finally {
30.             RpcInternalContext.removeContext();
31.             RpcInternalContext.popContext();
32.         }
33.     }

        调用父类ClientProxyInvoker的invoke方法,该方法为一个模板方法,定义了远程服务调用的具体步骤,如包装请求、产生调用开始事件、实际的服务调用、产生调用结束事件、包装响应。其中:

        1.   包装请求主要是根据用户设置的参数值设置SofaRequest实例相关属性,如目标服务名、序列化类型、调用类型、调用级别超时时间、调用级别回调函数、目标URL等;

        2.   产生调用开始事件主要是发布ClientStartInvokeEvent事件;

        3.   实际的服务调用主要是调用Cluster接口的某个实现(此处为FailoverCluster)的invoke方法,完成实际的远程服务调用;

        4.   产生调用结束事件主要是发布ClientEndInvokeEvent事件;

        5.   包装响应主要是处理返回的响应结果SofaResponse,如ResponseFuture的处理、透传数据的处理等;

        我们主要关注第3步,实际的服务调用。先看一下FailoverCluster父类AbstractCluster的invoke方法:

1.      public SofaResponse invoke(SofaRequestrequest) throws SofaRpcException {
2.          SofaResponse response = null;
3.          try {
4.              // 做一些初始化检查,例如未连接可以连接
5.              checkClusterState();
6.              // 开始调用
7.              countOfInvoke.incrementAndGet(); //计数+1        
8.              response = doInvoke(request);
9.              return response;
10.         } catch (SofaRpcException e) {
11.             // 客户端收到异常(客户端自己的异常)
12.             throw e;
13.         } finally {
14.             countOfInvoke.decrementAndGet(); //计数-1
15.         }
16.     }

        又是一个模板方法,主要关注doInvoke方法:

1.  public SofaResponse doInvoke(SofaRequestrequest) throws SofaRpcException {
2.          String methodName =request.getMethodName();
3.          int retries =consumerConfig.getMethodRetries(methodName);
4.          int time = 0;
5.          SofaRpcException throwable = null;// 异常日志
6.          List<ProviderInfo>invokedProviderInfos = new ArrayList<ProviderInfo>(retries + 1);
7.          do {
8.              ProviderInfo providerInfo = select(request,invokedProviderInfos);
9.              try {
10.                 SofaResponse response =filterChain(providerInfo, request);
11.                 if (response != null) {
12.                     ……                    return response;
13.                 } else {
14.                     throwable = newSofaRpcException(……);
15.                 }
16.             } catch (SofaRpcException e) { // 服务端异常+ 超时异常才发起rpc异常重试
17.                 if (e.getErrorType() ==RpcErrorType.SERVER_BUSY
18.                     || e.getErrorType() ==RpcErrorType.CLIENT_TIMEOUT) {
19.                     throwable = e;
20.                     time++;
21.                 } else {
22.                     throw e;
23.                 }
24.             } catch (Exception e) { // 其它异常不重试
25.                 throw new SofaRpcException(……);
26.             } finally {
27.                 if(RpcInternalContext.isAttachmentEnable()) {
28.                     RpcInternalContext.getContext().setAttachment(RpcConstants.INTERNAL_KEY_INVOKE_TIMES,
29.                         time + 1); // 重试次数
30.                 }
31.             }
32.             invokedProviderInfos.add(providerInfo);
33.         } while (time <= retries);
34.  
35.         throw throwable;
36.     }

        在FailoverCluster类invoke方法中,首先,获取调用的方法名称。然后,获取失败时重试次数,0表示不重试。最后,通过do{}while循环调用远程服务,至少调用一次。如果设置了重试次数,则在重试次数范围内,每次根据规则选择不同的服务提供者,多次调用,直至调用成功或所有调用都失败。

        循环调用远程服务的主要处理逻辑如下:

        一、  访问路径路由

        调用AbstractCluster类select方法,根据规则进行负载均衡,选择服务提供者:

1.  protected ProviderInfo select(SofaRequestmessage, List<ProviderInfo> invokedProviderInfos)
2.          throws SofaRpcException {
3.          // 粘滞连接,当前连接可用
4.          if (consumerConfig.isSticky()) {
5.              if (lastProviderInfo != null) {
6.                  ProviderInfo providerInfo =lastProviderInfo;
7.                  ClientTransport lastTransport =connectionHolder.getAvailableClientTransport(providerInfo);
8.                  if (lastTransport != null&& lastTransport.isAvailable()) {
9.                      checkAlias(providerInfo,message);
10.                     return providerInfo;
11.                 }
12.             }
13.         }
14.         // 原始服务列表数据 --> 路由结果
15.         List<ProviderInfo> providerInfos =routerChain.route(message, null);
16.         if (CommonUtils.isEmpty(providerInfos)){
17.             thrownoAvailableProviderException(message.getTargetServiceUniqueName());
18.         }
19.         if(CommonUtils.isNotEmpty(invokedProviderInfos) && providerInfos.size()> invokedProviderInfos.size()) { // 总数大于已调用数
20.             providerInfos.removeAll(invokedProviderInfos);//已经调用异常的本次不再重试
21.         }
22.  
23.         String targetIP = null;
24.         ProviderInfo providerInfo;
25.         RpcInternalContext context =RpcInternalContext.peekContext();
26.         if (context != null) {
27.             targetIP = (String)RpcInternalContext.getContext().getAttachment(RpcConstants.HIDDEN_KEY_PINPOINT);
28.         }
29.         if (StringUtils.isNotBlank(targetIP)) {
30.             // 如果指定了调用地址
31.             providerInfo =selectPinpointProvider(targetIP, providerInfos);
32.             if (providerInfo == null) {
33.                 // 指定的不存在
34.                 throw unavailableProviderException(message.getTargetServiceUniqueName(),targetIP);
35.             }
36.             ClientTransport clientTransport =selectByProvider(message, providerInfo);
37.             if (clientTransport == null) {
38.                 // 指定的不存在或已死,抛出异常
39.                 throwunavailableProviderException(message.getTargetServiceUniqueName(), targetIP);
40.             }
41.             return providerInfo;
42.         } else {
43.             do {
44.                 // 再进行负载均衡筛选
45.                 providerInfo = loadBalancer.select(message,providerInfos);
46.                 ClientTransport transport =selectByProvider(message, providerInfo);
47.                 if (transport != null) {
48.                     return providerInfo;
49.                 }
50.                 providerInfos.remove(providerInfo);
51.             } while (!providerInfos.isEmpty());
52.         }
53.         thrownoAvailableProviderException(message.getTargetServiceUniqueName());
54.     }

        1.   如果服务消费者的sticky为true,则表示粘滞连接,即如果当前连接可用,使用当前连接。否则,继续选择服务提供者。此处sticky为false,继续:

        2.   调用com.alipay.sofa.rpc.client.RouterChain类route方法,根据SofaRequest请求选择所有服务提供者,并存入providerInfos列表中:

1.      public List<ProviderInfo>route(SofaRequest request, List<ProviderInfo> providerInfos) {
2.          for (Router router : routers) {
3.              providerInfos =router.route(request, providerInfos);
4.          }
5.          return providerInfos;
6.      }

           ★ 依次遍历所有的Router(此处只存在一个Router,即DirectUrlRouter),调用每个Router的route方法选择服务提供者。此处调用DirectUrlRouter的route方法:

1.      public List<ProviderInfo>route(SofaRequest request, List<ProviderInfo> providerInfos) {
2.          AddressHolder addressHolder =consumerBootstrap.getCluster().getAddressHolder();
3.          if (addressHolder != null) {
4.              List<ProviderInfo> current =addressHolder.getProviderInfos(RpcConstants.ADDRESS_DIRECT_GROUP);
5.              if (providerInfos != null) {
6.                  providerInfos.addAll(current);
7.              } else {
8.                  providerInfos = current;
9.              }
10.         }
11.         recordRouterWay(RPC_DIRECT_URL_ROUTER);
12.         return providerInfos;
13.     }

            ★ 根据服务列表的标签(此处为_DIRECT),获取某分组的服务列表,并增加到服务提供者信息列表providerInfos中。

        3.   当服务提供者的数量大于已经调用过服务次数,则去掉已经调用异常的服务提供者,本次不再重试。

        4.   获取当前线程的RpcInternalContext实例,然后从context的attachments中获取key为.pinpoint的目标IP地址targetIP;

        5.   如果targetIP为空,则循环执行:

            1)   调用负载均衡器LoadBalancer的select方法进行筛选:

1.      public ProviderInfo select(SofaRequestrequest, List<ProviderInfo> providerInfos) throws SofaRpcException {
2.          if (providerInfos.size() == 0) {
3.              throw noAvailableProviderException(request.getTargetServiceUniqueName());
4.          }
5.          if (providerInfos.size() == 1) {
6.              return providerInfos.get(0);
7.          } else {
8.              return doSelect(request,providerInfos);
9.          }
10.     }

                ★  如果服务提供者数量为0,则直接抛出noAvailableProviderException异常;

                ★  如果服务提供者数量为1,则直接返回那个唯一的服务提供者;

                ★  如果服务提供者数量大于1,则调用doSelect方法,根据某种规则从服务提供者列表中选择一个服务提供者。例如:随机负载均衡器RandomLoadBalancer,则全部服务提供者列表按权重随机选择;轮询负载均衡器RoundRobinLoadBalancer,则全部服务提供者列表按方法级进行轮询,互不影响;其它类型负载均衡器自行查看。

                ★  此处服务提供者数量为1,直接返回服务提供者列表中那个唯一的服务提供者。

            2)   调用selectByProvider方法,为选择的服务提供者providerInfo得到连接;

1.      protected ClientTransportselectByProvider(SofaRequest message, ProviderInfo providerInfo) {
2.          ClientTransport transport =connectionHolder.getAvailableClientTransport(providerInfo);
3.          if (transport != null) {
4.              if (transport.isAvailable()) {
5.                  lastProviderInfo =providerInfo;
6.                  checkAlias(providerInfo, message); //检查分组
7.                  return transport;
8.              } else {
9.                  connectionHolder.setUnavailable(providerInfo,transport);
10.             }
11.         }
12.         return null;
13.     }

                ★  调用connectionHolder(此外为AllConnectConnectionHolder实例)的getAvailableClientTransport方法,根据providerInfo查找存活的ClientTransport,此处查找到RestClientTransport实例;

                ★  如果RestClientTransport实例不可用,则设置connectionHolder为不可用,返回null。否则,返回可用的RestClientTransport实例。

            3)   如果获取到RestClientTransport实例,则返回选择的providerInfo。如果没有获取到RestClientTransport实例,则从providerInfos列表中删除刚才选择的providerInfo。如果此时providerInfos不为空,则下一个循环,继续选择可用的providerInfo。如果没有可用的providerInfo,则抛noAvailableProviderException异常。

        6.   如果targetIP不为空,表示指定了服务调用地址,则调用selectPinpointProvider方法,从providerInfos列表中targetIP对应的服务提供者。然后调用selectByProvider方法,为服务提供者providerInfo得到连接。如果ClientTransport实例为null,则抛出unavailableProviderException异常。如果ClientTransport实例不为null,则返回providerInfo实例。

        此处targetIP为空,所以按照targetIP为空的逻辑处理,返回选择的providerInfo实例,此实例的字符串值为127.0.0.1:8341,为服务提供者的地址。

        二、  调用执行链

        以选择的providerInfo和SofaRequest实例为参数,调用FailoverCluster类filterChain方法,发起远程服务调用链:

1.      protected SofaResponsefilterChain(ProviderInfo providerInfo, SofaRequest request) throwsSofaRpcException {
2.          RpcInternalContext.getContext().setProviderInfo(providerInfo);
3.          return filterChain.invoke(request);
4.      }

        对于FilterChain的设计原理,可以参考《FilterChain》,在此不详述。

        在此案例中,过滤器执行链只存在两个节点。第一个节点是由过滤器com.alipay.sofa.rpc.filter.ConsumerExceptionFilter封装成的FilterInvoker调用器。第二个节点是com.alipay.sofa.rpc.filter.ConsumerInvoker,此类为FilterInvoker子类。

        首先执行过滤器链中第一个节点,ConsumerExceptionFilter过滤器主要用来捕获消费者调用异常,所以只是在try{}catch(){}代码块中调用下一个节点ConsumerInvoker的invoke方法;

        接着执行过滤器链中第二个节点,也是最后一个节点,此处为ConsumerInvoker的invoke方法:

1.      public SofaResponse invoke(SofaRequestsofaRequest) throws SofaRpcException {
2.          // 设置下服务器应用
3.          ProviderInfo providerInfo =RpcInternalContext.getContext().getProviderInfo();
4.          String appName =providerInfo.getStaticAttr(ProviderInfoAttrs.ATTR_APP_NAME);
5.          if (StringUtils.isNotEmpty(appName)) {
6.              sofaRequest.setTargetAppName(appName);
7.          }
8.   
9.          // 目前只是通过client发送给服务端
10.         returnconsumerBootstrap.getCluster().sendMsg(providerInfo, sofaRequest);
11.     }

        ConsumerInvoker类invoke方法主要处理逻辑如下:

  • 通过RpcInternalContext(基于ThreadLocal的内部使用的上下文)获取当前线程的RpcInternalContext实例。
  • 通过RpcInternalContext实例获取服务提供者信息providerInfo;
  • 由于是调用restful风格的服务,所以,此处调用RestConsumerBootstrap的getCluster方法,获取Cluster接口实现FailoverCluster的实例。
  • 然后调用FailoverCluster的sendMsg方法:
1.      public SofaResponse sendMsg(ProviderInfoproviderInfo, SofaRequest request) throws SofaRpcException {
2.          ClientTransport clientTransport =connectionHolder.getAvailableClientTransport(providerInfo);
3.          if (clientTransport != null &&clientTransport.isAvailable()) {
4.              return doSendMsg(providerInfo,clientTransport, request);
5.          } else {
6.              throwunavailableProviderException(request.getTargetServiceUniqueName(),providerInfo.getOriginUrl());
7.          }
8.      }

        调用ConnectionHolder(此处为AllConnectConnectionHolder实例)的getAvailableClientTransport方法,根据provider查找可用的ClientTransport。

1.  public ClientTransportgetAvailableClientTransport(ProviderInfo providerInfo) {
2.          // 先去存活列表
3.          ClientTransport transport =aliveConnections.get(providerInfo);
4.          if (transport != null) {
5.              return transport;
6.          }
7.          // 再去亚健康列表
8.          transport =subHealthConnections.get(providerInfo);
9.          if (transport != null) {
10.             return transport;
11.         }
12.         // 最后看看是否第一次调用未初始化
13.         transport =uninitializedConnections.get(providerInfo);
14.         if (transport != null) {
15.             // 未初始化则初始化
16.             synchronized (this) {
17.                 transport =uninitializedConnections.get(providerInfo);
18.                 if (transport != null) {
19.                     initClientTransport(consumerConfig.getInterfaceId(),providerInfo, transport);
20.                     uninitializedConnections.remove(providerInfo);
21.                 }
22.                 returngetAvailableClientTransport(providerInfo);
23.             }
24.         }
25.         return null;
26.     }

       查找可用的ClientTransport过程上述代码注释所述。
       此处查找到可用的ClientTransport为RestClientTransport,然后调用doSendMsg方法:
1.  protected SofaResponsedoSendMsg(ProviderInfo providerInfo, ClientTransport transport,
2.                                       SofaRequestrequest) throws SofaRpcException {
3.          RpcInternalContext context =RpcInternalContext.getContext();
4.          // 添加调用的服务端远程地址
5.          RpcInternalContext.getContext().setRemoteAddress(providerInfo.getHost(),providerInfo.getPort());
6.          try {
7.              checkProviderVersion(providerInfo, request);// 根据服务端版本特殊处理
8.              String invokeType =request.getInvokeType();
9.              int timeout =resolveTimeout(request, consumerConfig, providerInfo);
10.  
11.             SofaResponse response = null;
12.             // 同步调用
13.             if (RpcConstants.INVOKER_TYPE_SYNC.equals(invokeType)){
14.                 long start =RpcRuntimeContext.now();
15.                 try {
16.                     response = transport.syncSend(request,timeout);
17.                 } finally {
18.                     if (RpcInternalContext.isAttachmentEnable()){
19.                         long elapsed =RpcRuntimeContext.now() - start;
20.                         context.setAttachment(RpcConstants.INTERNAL_KEY_CLIENT_ELAPSE,elapsed);
21.                     }
22.                 }
23.             }
24.             // 单向调用
25.             else if(RpcConstants.INVOKER_TYPE_ONEWAY.equals(invokeType)) {
26.                 long start =RpcRuntimeContext.now();
27.                 try {
28.                     transport.oneWaySend(request,timeout);
29.                     response = newSofaResponse();
30.                 } finally {
31.                     if(RpcInternalContext.isAttachmentEnable()) {
32.                         long elapsed =RpcRuntimeContext.now() - start;
33.                         context.setAttachment(RpcConstants.INTERNAL_KEY_CLIENT_ELAPSE,elapsed);
34.                     }
35.                 }
36.             }
37.             // Callback调用
38.             else if(RpcConstants.INVOKER_TYPE_CALLBACK.equals(invokeType)) {
39.                 // 调用级别回调监听器
40.                 SofaResponseCallback sofaResponseCallback= request.getSofaResponseCallback();
41.                 if (sofaResponseCallback ==null) {
42.                     SofaResponseCallbackmethodResponseCallback = consumerConfig
43.                         .getMethodOnreturn(request.getMethodName());
44.                     if (methodResponseCallback !=null) { // 方法的Callback
45.                         request.setSofaResponseCallback(methodResponseCallback);
46.                     }
47.                 }
48.                 transport.asyncSend(request,timeout);
49.                 response = new SofaResponse();
50.             }
51.             // Future调用
52.             else if(RpcConstants.INVOKER_TYPE_FUTURE.equals(invokeType)) {
53.                 // 开始调用
54.                 ResponseFuture future =transport.asyncSend(request, timeout);
55.                 // 放入线程上下文
56.                 RpcInternalContext.getContext().setFuture(future);
57.                 response = new SofaResponse();
58.             } else {
59.                 throw newSofaRpcException(RpcErrorType.CLIENT_UNDECLARED_ERROR, "Unknown invoketype:" + invokeType);
60.             }
61.             return response;
62.         } catch (SofaRpcException e) {
63.             throw e;
64.         } catch (Throwable e) { // 客户端其它异常
65.             throw newSofaRpcException(RpcErrorType.CLIENT_UNDECLARED_ERROR, e);
66.         }
67.     }

        doSendMsg方法的执行过程如上述代码注释所述。

        此次请求的调用方式为sync,即同步调用。所以,调用RestClientTransport类syncSend方法发送服务请求。实际的服务请求操作在doInvokeSync方法中实现:

1.  protected SofaResponsedoInvokeSync(SofaRequest request, int timeoutMillis)
2.          throws InvocationTargetException,IllegalAccessException {
3.          SofaResponse response = newSofaResponse();
4.          Method method = getMethod(request);
5.          if (method == null) {
6.              throw newSofaRpcException(RpcErrorType.CLIENT_UNDECLARED_ERROR,
7.                  "Not found method :" +request.getInterfaceName() + "." + request.getMethodName());
8.          }
9.          Object o = method.invoke(proxy,request.getMethodArgs());
10.         response.setAppResponse(o);
11.         return response;
12.     }

        创建SOFA RPC远程服务响应SofaResponse实例;

        根据SOFA RPC服务请求获取远程服务对应的方法;

        通过反射机制实现方法调用,其中proxy为PersonService接口的代理对象,handler为实现了Java动态代理java.lang.reflect.InvocationHandler接口的org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy。

        实际调用ClientProxy类invoke方法:

1.  public Object invoke(Object o, Methodmethod, Object[] args)
2.             throws Throwable
3.     {
4.        // equals and hashCode were added forcases where the proxy is added to
5.        // collections. The Spring transactionmanagement, for example, adds
6.        // transactional Resources to aCollection, and it calls equals and
7.        // hashCode.
8.   
9.        MethodInvoker clientInvoker =methodMap.get(method);
10.       if (clientInvoker == null)
11.       {
12.          if(method.getName().equals("equals"))
13.          {
14.             return this.equals(o);
15.          }
16.          else if (method.getName().equals("hashCode"))
17.          {
18.             return this.hashCode();
19.          }
20.          else if(method.getName().equals("toString") && (args == null ||args.length == 0))
21.          {
22.             return this.toString();
23.          }
24.       }
25.  
26.       if (clientInvoker == null)
27.       {
28.          throw new RuntimeException("Couldnot find a method for: " + method);
29.       }
30.       return clientInvoker.invoke(args);
31.    }

        根据method获取MethodInvoker接口的实现,此外为org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker。

        调用ClientInvoker的invoke方法:

1.     public Object invoke(Object[] args)
2.     {
3.        ClientInvocation request =createRequest(args);
4.        ClientResponse response =(ClientResponse)request.invoke();
5.        ClientContext context = newClientContext(request, response, entityExtractorFactory);
6.        return extractor.extractEntity(context,null);
7.     }

        根据请求参数创建ClientInvocation实例;

        调用ClientInvocation的invoke方法:

1.  public Response invoke()
2.     {
3.        Providers current =ResteasyProviderFactory.getContextData(Providers.class);
4.        ResteasyProviderFactory.pushContext(Providers.class,configuration);
5.        try
6.        {
7.           ClientRequestContextImplrequestContext = new ClientRequestContextImpl(this);
8.           ……
9.           // spec requires that aborted responsego through filter/interceptor chains.
10.          ClientResponse response = aborted;
11.          if (response == null)
12.              response = client.httpEngine().invoke(this);
13.  
14.          response.setProperties(configuration.getMutableProperties());
15.          ……
16.          return response;
17.       }
18.       finally
19.       {
20.          ……
21.       }
22.    }

        调用org.jboss.resteasy.client.jaxrs.ResteasyClient类httpEngine方法,获取org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine实例;

        调用ApacheHttpClient4Engine类invoke方法:

1.     public ClientResponseinvoke(ClientInvocation request)
2.     {
3.        String uri = request.getUri().toString();
4.        final HttpRequestBase httpMethod =createHttpMethod(uri, request.getMethod());
5.        final HttpResponse res;
6.        try
7.        {
8.           loadHttpMethod(request, httpMethod);
9.   
10.          res = httpClient.execute(httpMethod,httpContext);
11.       }
12.       catch (Exception e)
13.       {
14.          throw newProcessingException("Unable to invoke request", e);
15.       }
16.       finally
17.       {
18.          cleanUpAfterExecute(httpMethod);
19.       }
20.  
21.       ……
22.    }

        根据请求URL(例如:http://127.0.0.1:8341/webapi/rest/person/sayName/Mike)和请求方法名称,构造org.apache.http.client.methods.HttpRequestBase请求对象:

        例如:请求对象的字符串值为:

        GET http://127.0.0.1:8341/webapi/rest/person/sayName/Mike HTTP/1.1

        最后,调用org.apache.http.impl.client.DefaultHttpClient类execute方法,完成restful风格的远程服务调用。

        到这步为止,大家可以看到,SOFA RPC客户端底层使用HttpClient调用restful服务,具体实现细节不在详述。

        再回看PersonService接口的JDK代理对象的handler:JDKInvocationHandler。该类的invoke方法:

1.  public Object invoke(Object proxy, Methodmethod, Object[] paramValues)
2.          throws Throwable {
3.          String methodName = method.getName();
4.          Class[] paramTypes =method.getParameterTypes();
5.          ……
6.          SofaRequest sofaRequest =MessageBuilder.buildSofaRequest(method.getDeclaringClass(),
7.              method, paramTypes, paramValues);
8.          SofaResponse response =proxyInvoker.invoke(sofaRequest);
9.          if (response.isError()) {
10.             throw new SofaRpcException(……);
11.         }
12.         Object ret = response.getAppResponse();
13.         if (ret instanceof Throwable) {
14.             throw (Throwable) ret;
15.         } else {
16.             if (ret == null) {
17.                 returnClassUtils.getDefaultArg(method.getReturnType());
18.             }
19.             return ret;
20.         }
21.     }

        在这里采用同步调用方式,所以线程阻塞在以下代码处,等待服务端接收请求,根据请求进行业务处理,最后返回处理结果:

1.  SofaResponse response =proxyInvoker.invoke(sofaRequest);

        服务端响应请求的流程在《服务端响应流程》中详述,在此略过。

        当服务端处理完客户端请求,返回处理结果SofaResponse。调用getAppResponse方法,获取接口所需数据类型的返回结果,此处为String类型,值为:hi Mike!。

        至此,客户端以本地Java调用方式访问远程服务的调用流程完成。


猜你喜欢

转载自blog.csdn.net/beyondself_77/article/details/80862734