11. --- SOFARPC source code analysis data transparent transmission is implemented?

First put chestnuts, so that we facilitate testing:
Service end

public static void main(String[] args) {
    ServerConfig serverConfig = new ServerConfig()
        .setProtocol("bolt") // 设置一个协议,默认bolt
        .setPort(12200) // 设置一个端口,默认12200
        .setDaemon(false); // 非守护线程

    ProviderConfig<HelloService> providerConfig = new ProviderConfig<HelloService>()
        .setInterfaceId(HelloService.class.getName()) // 指定接口
        .setRef(new HelloServiceImpl()) // 指定实现
        .setServer(serverConfig); // 指定服务端

    providerConfig.export(); // 发布服务
}

public class HelloServiceImpl implements HelloService {

    private final static Logger LOGGER = LoggerFactory.getLogger(HelloServiceImpl.class);

    @Override
    public String sayHello(String string) {
        LOGGER.info("Server receive: " + string);

        // 获取请求透传数据并打印
        System.out.println("service receive reqBag -> " + RpcInvokeContext.getContext().getRequestBaggage("req_bag"));
        // 设置响应透传数据到当前线程的上下文中
        RpcInvokeContext.getContext().putResponseBaggage("req_bag", "s2c");

        return "hello " + string + " !";
    }
}

client end

public static void main(String[] args) {
    ConsumerConfig<HelloService> consumerConfig = new ConsumerConfig<HelloService>()
        .setInterfaceId(HelloService.class.getName()) // 指定接口
        .setProtocol("bolt") // 指定协议
        .setDirectUrl("bolt://127.0.0.1:12200") // 指定直连地址
        .setConnectTimeout(10 * 1000);

    RpcInvokeContext.getContext().putRequestBaggage("req_bag", "a2bbb");

    HelloService helloService = consumerConfig.refer();

    while (true) {
        System.out.println("service receive reqBag -> " + RpcInvokeContext.getContext().getResponseBaggage("req_bag"));
        try {
            LOGGER.info(helloService.sayHello("world"));
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

Through the above we can see chestnuts entire process should be:

  1. The client needs to put into the transparent transmission of data to requestBaggage, and then call the server
  2. The server transparently transmits the data acquisition request and the print HelloServiceImpl, and placed in the response data to the responseBaggage
  3. The client receives the pass-through data

So let's begin to explain the source code from the client.

Client data transparently to the server

First, before referring a client to be set putRequestBaggage, then when the client reference calls ClientProxyInvoker # invoke method.

As follows:
ClientProxyInvoker the Invoke #

public SofaResponse invoke(SofaRequest request) throws SofaRpcException {
    ....
        // 包装请求
        decorateRequest(request);
       ....
}

By calling decorateRequest calls to decorateRequest subclass of DefaultClientProxyInvoker.

DefaultClientProxyInvoker#decorateRequest

protected void decorateRequest(SofaRequest request) {
    ....
    RpcInvokeContext invokeCtx = RpcInvokeContext.peekContext();
    RpcInternalContext internalContext = RpcInternalContext.getContext();
    if (invokeCtx != null) {
       ....
        // 如果用户指定了透传数据
        if (RpcInvokeContext.isBaggageEnable()) {
            // 需要透传
            BaggageResolver.carryWithRequest(invokeCtx, request);
            internalContext.setAttachment(HIDDEN_KEY_INVOKE_CONTEXT, invokeCtx);
        }
    }
    ....
} 

In decorateRequest method will first check where there is no open transparent transmission of data, if turned on, then call BaggageResolver # carryWithRequest, the transparent transmission of data to be placed inside to request

BaggageResolver#carryWithRequest

public static void carryWithRequest(RpcInvokeContext context, SofaRequest request) {
    if (context != null) {
          //获取所有的透传数据
        Map<String, String> requestBaggage = context.getAllRequestBaggage();
        if (CommonUtils.isNotEmpty(requestBaggage)) { // 需要透传
            request.addRequestProp(RemotingConstants.RPC_REQUEST_BAGGAGE, requestBaggage);
        }
    }
}

This method which is done transparently transmit all the data acquired, and then placed into RequestProp inside, so that when the transmission request will be sent to the server.

Server to accept pass-through data

Server call flow is as follows:

BoltServerProcessor->FilterChain->ProviderExceptionFilter->FilterInvoker->RpcServiceContextFilter->FilterInvoker->ProviderBaggageFilter->FilterInvoker->ProviderTracerFilter->ProviderInvoker 

So you can know from the call chain above, when the server will be referenced through ProviderBaggageFilter filter, we look at the following filters do anything:

ProviderBaggageFilter#invoke

public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
    SofaResponse response = null;
    try {
        //从request中获取透传数据存入到requestBaggage中
        BaggageResolver.pickupFromRequest(RpcInvokeContext.peekContext(), request, true);
        response = invoker.invoke(request);
    } finally {
        if (response != null) {
            BaggageResolver.carryWithResponse(RpcInvokeContext.peekContext(), response);
        }
    }
    return response;
}

ProviderBaggageFilter calls BaggageResolver#pickupFromRequestto get data from the request

BaggageResolver#pickupFromRequest

public static void pickupFromRequest(RpcInvokeContext context, SofaRequest request, boolean init) {
    if (context == null && !init) {
        return;
    }
    // 解析请求 
    Map<String, String> requestBaggage = (Map<String, String>) request
        .getRequestProp(RemotingConstants.RPC_REQUEST_BAGGAGE);
    if (CommonUtils.isNotEmpty(requestBaggage)) {
        if (context == null) {
            context = RpcInvokeContext.getContext();
        }
        context.putAllRequestBaggage(requestBaggage);
    }
}

Finally will be called finally ProviderBaggageFilter invoke method inside BaggageResolver#carryWithResponsethe transparent transmission of data in response to written response back inside.

public static void carryWithResponse(RpcInvokeContext context, SofaResponse response) {
    if (context != null) {
        Map<String, String> responseBaggage = context.getAllResponseBaggage();
        if (CommonUtils.isNotEmpty(responseBaggage)) {
            String prefix = RemotingConstants.RPC_RESPONSE_BAGGAGE + ".";
            for (Map.Entry<String, String> entry : responseBaggage.entrySet()) {
                response.addResponseProp(prefix + entry.getKey(), entry.getValue());
            }
        }
    }
}

Client receives the response data passthrough

Finally, the client will call decorateResponse get write-back of data in response ClientProxyInvoker # invoke method inside.

public SofaResponse invoke(SofaRequest request) throws SofaRpcException {
        ....
     // 包装响应
     decorateResponse(response);
        ....
}

decorateResponse is implemented in a subclass DefaultClientProxyInvoker:

DefaultClientProxyInvoker#decorateResponse

protected void decorateResponse(SofaResponse response) {
   ....
    //如果开启了透传
    if (RpcInvokeContext.isBaggageEnable()) {
        BaggageResolver.pickupFromResponse(invokeCtx, response, true);
    }
   ....
}

This method calls inside BaggageResolver # pickupFromResponse

public static void pickupFromResponse(RpcInvokeContext context, SofaResponse response, boolean init) {
    if (context == null && !init) {
        return;
    }
    Map<String, String> responseBaggage = response.getResponseProps();
    if (CommonUtils.isNotEmpty(responseBaggage)) {
        String prefix = RemotingConstants.RPC_RESPONSE_BAGGAGE + ".";
        for (Map.Entry<String, String> entry : responseBaggage.entrySet()) {
            if (entry.getKey().startsWith(prefix)) {
                if (context == null) {
                    context = RpcInvokeContext.getContext();
                }
                //因为entry的key里面会包含rpc_resp_baggage,所以需要截取掉
                context.putResponseBaggage(entry.getKey().substring(prefix.length()),
                    entry.getValue());
            }
        }
    }
}

This method of obtaining all the response which the data pass-through, and then put into the ResponseBaggage.

Here SOFARPC pass-through data analysis completed on the

Guess you like

Origin www.cnblogs.com/luozhiyun/p/11388450.html