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

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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

任性之闲来无事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值