A, HttpRequestWrapper

public class HttpRequestWrapper implements HttpRequest {
    private finalHttpRequest request; } In the first article, we looked at the RestTemplate source code and reviewed the execution process: Create a ClientHttpRequest object using the createRequest method of the ClientHttpRequestFactory, and then call the execute method of the object. When there is an interceptor and the interceptor does not implement the request sending function, The code execution logic looks like this: <1> create InterceptingClientHttpRequestFactory and call the createRequest method, this method returns an object InterceptingClientHttpRequest <2> call InterceptingClientHttpRequest the execute method, is to create a InterceptingRequestExecution, And call the execute method of InterceptingRequestExecution <3> call all the interceptors intercept method, and finally reach the InterceptingRequestExecution the execute methodelseLogic"4> use SimpleClientHttpRequestFactory createRequest method create a SimpleStreamingClientHttpRequest object, Send the request is SimpleStreamingClientHttpRequest HttpRequest implementation class, so HttpRequestWrapper role is very clear, on the HttpRequest packing:public class HttpRequestWrapper implements HttpRequest {
	    private finalHttpRequest request; } Typical decorator mode, which enhances HttpRequest objects passed in and saved. Let's take a look at the implementation in the Ribbon:public class ServiceRequestWrapper extends HttpRequestWrapper {
	private final ServiceInstance instance;
	private final LoadBalancerClient loadBalancer;

	@Override
	public URI getURI(a) {
		URI uri = this.loadBalancer.reconstructURI(this.instance, getRequest().getURI());
		returnuri; }} reconstructURI (LoadBalancerClient's reconstructURI method) {reconstructURI (LoadBalancerClient's reconstructURI method);}} reconstructURI (LoadBalancerClient's reconstructURI method); The reconstructURI method is used to replace the host with the service name selected by the load balancer, but we'll talk about what the LoadBalancerClient does laterCopy the code

2. LoadBalancerRequest analysis

LoadBalancerRequest is a functional interface. Let's look at its interface:public interface LoadBalancerRequest<T> {
        T apply(ServiceInstance instance) throws Exception; } Pass a ServiceInstance and return a generic T, which in SpringCloud's integrated Ribbon is the response entity ClientHttpResponse class in RestTemplate, So the Apply method actually says perform a load balancing request, and let's look at the implementationpublic LoadBalancerRequest<ClientHttpResponse> createRequest(
        final HttpRequest request, final byte[] body,
        final ClientHttpRequestExecution execution) {
    return instance -> {
        // Some of the code is abbreviated
        HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
                this.loadBalancer);
        returnexecution.execute(serviceRequest, body); }; } createRequest creates an inner class of type LoadBalancerRequest. Let's look at the apply method implemented in this inner class. At last, by the execute method to perform the requested ClientHttpRequestExecution, back to the first article in the RestTemplate interceptors based on the realization of the chain of responsibility mode, when all the interceptors are found by the iterator is performed, Using the execute method of the incoming HttpRequest to really send the request, you can see, actually said ServiceRequestWrapper is used to send the request, but the inside rewrite the getURI method, And hold a reference to the native HttpRequest object, so the real principle is to use the overwritten getURI to get the URI that actually sent the request, Finally using native HttpRequest object to send the createRequest method is LoadBalancerRequestFactory request, we take a look at LoadBalancerRequestFactory source code:// Some of the code is abbreviated
public class LoadBalancerRequestFactory {
	private LoadBalancerClient loadBalancer;
	public LoadBalancerRequest<ClientHttpResponse> createRequest(
			final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) {
		return instance -> {
			HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
					this.loadBalancer);
			returnexecution.execute(serviceRequest, body); }; }}Copy the code

LoadBalancerClient analysis

LoadBalancerClient (LoadBalancerClient, LoadBalancerClient, LoadBalancerClient, LoadBalancerClient, LoadBalancerClient, LoadBalancerClient, LoadBalancerClient, LoadBalancerClient, LoadBalancerClient, LoadBalancerClient, LoadBalancerClient, LoadBalancerClientpublic interface LoadBalancerClient extends ServiceInstanceChooser {
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

	<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest
       
         request)
        throws IOException;

	URI reconstructURI(ServiceInstance instance, URI original); } execute method is used to actually execute the request. The main logic in this method is to get a load balancer according to serviceId. Yes, each type of service has its own load balancer. Each service name has its own Spring context in the Map, in which the relevant configuration of the service is saved. In the later analysis, we can see that the LoadBalancer is obtained according to the service name in the Map to find the corresponding Spring context. ReconstructURI LoadBalancer reconstructURI LoadBalancer reconstructURI LoadBalancer reconstructURI LoadBalancer reconstructURI LoadBalancer reconstructURI LoadBalancer reconstructURI LoadBalancer reconstructURI LoadBalancer Said the reconstructURI method is used to through the load balancer selected service domain replace the host only one LoadBalancerClient interface implementation class RibbonLoadBalancerClient, Let's look at the implementation of the execute method call chain:public class RibbonLoadBalancerClient implements LoadBalancerClient {
    public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
			throws IOException {
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
		Server server = getServer(loadBalancer, hint);
		RibbonServer ribbonServer = new RibbonServer(serviceId, server,
				isSecure(server, serviceId),
				serverIntrospector(serviceId).getMetadata(server));
		return execute(serviceId, ribbonServer, request);
	}
    
    public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest
       
         request)
        throws IOException {
		Server server = null;
		if (serviceInstance instanceof RibbonServer) {
			server = ((RibbonServer) serviceInstance).getServer();
		}
        T returnVal = request.apply(serviceInstance);
        returnreturnVal; }} analysis: the first execute method does three things:1< span style = "max-width: 100%; clear: 100%; clear: 100%;2> Use the IRule load balancing policy of the found load balancer to find an appropriate Server from the list of saved services, namely the implementation of the getServer method <3> Wrap the Server as RibbonServer. RibbonServer saves serviceId, i.e. service name, on the basis of the original Server. For example, shopping cart service. The three steps should be easy to understand. When RibbonServer is obtained, the second execute method is called. The second execute method is also very simple, that is, the native Server is obtained. Then call the Apply method of LoadBalancerRequest, And apply method actually will call to our second section LoadBalancerRequestFactory LoadBalancerRequest createRequest method created in the implementation of class (inner classes), Finally using ClientHttpRequestExecution the execute method to perform the invocation chainCopy the code

LoadBalancerInterceptor

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
	private LoadBalancerClient loadBalancer;
	private LoadBalancerRequestFactory requestFactory;

    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) throws IOException {
		final URI originalUri = request.getURI();
		String serviceName = originalUri.getHost();
		return this.loadBalancer.execute(serviceName,
				this.requestFactory.createRequest(request, body, execution)); }} analysis: LoadBalancerInterceptor LoadBalancerInterceptor LoadBalancerInterceptor LoadBalancerInterceptor LoadBalancerInterceptor LoadBalancerInterceptor LoadBalancerInterceptor LoadBalancerInterceptor LoadBalancerInterceptor Interceptor method LoadBalancerClient intercept is used to perform the requested, by LoadBalancerRequestFactory createRequest method of interceptors in the incoming HttpRequest for packaging, The implementation class for the wrapper is ServiceRequestWrapper, which overrides the getURI method and uses the reconstructURI method of LoadBalancerClient to generate the final requested URLCopy the code

Five, the summary

The Ribbon source code and RestTemplate source code are analyzed one by one in four articles. I believe you have a deeper understanding of the Ribbon and RestTemplate principle. Here's a quick summary of the execution process for sending a request to the RestTemplate. <1> The RestTemplate uses doExecute as the entry point, Using the createRequest method creates a InterceptingClientHttpRequest request object, The object of InterceptingRequestExecution executeInternal method is used to complete the request execution < 2 > InterceptingRequestExecution the execute method based on the chain of responsibility pattern, Equestwrapper <3> In the Ribbon, when all the interceptors are completed, the request is sent to the request request request request request request request request request request request request request request request request request request request request request request request request request request request. Finally came to the execute method of nterceptingRequestExecution else inside, two lines inside the core code is as follows: ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method); return delegate.execute(); The getURI method of ServiceRequestWrapper is overridden by a load balancer to get the actual URL <4>. The LoadBalancerInterceptor is a Ribbon integrated with the RestTemplate interceptor. LoadBalanceClient is used to obtain load balancing url. In this method, there are three main steps: <1> Use the service name serviceId to go to SpringClientFactory and find the corresponding Spring context for this service. <2> Use the IRule load balancing policy of the found load balancer to find a suitable Server from the saved service list. The implementation of the getServer method <3> wraps the Server as RibbonServer, which saves the serviceId, the service name, such as the shopping cart service, on the basis of the original ServerCopy the code