Análisis del código fuente de RestTemplate y el uso del interceptor ClientHttpRequestInterceptor

Aquellos que han usado Spring deben tener una buena comprensión del uso de RestTemplate. Es una herramienta de cliente de solicitud Http proporcionada por Spring. Este blog no presentará el uso de RestTemplate, sino que solo analizará el flujo de llamadas de RestTemplate. Si desea conocer el uso de RestTemplate , Puede consultar la sección Spring MVC de la documentación oficial de Spring. Primero, veamos el diagrama de jerarquía de la clase RestTemplate y los métodos de llamada proporcionados. La siguiente RestTemplate proporciona muchas API para que las llamemos, y solo una parte se muestra a continuación:

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
    ......
   return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)throws RestClientException {
    ......
    return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
}
......

Como puede verse en los métodos proporcionados anteriormente, finalmente llamaron al método execute (). A continuación, observamos la lógica del método execute ():

public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
    //调用UriTemplateHandler对URI进行处理
    URI expanded = getUriTemplateHandler().expand(url, uriVariables);
    //调用doExecuute()方法
    return doExecute(expanded, method, requestCallback, responseExtractor);
}

En el método execute (), el URI es procesado primero por UriTemplateHandler, y el URI se extiende con variables URI. A continuación, se muestra el UriTemplateHandler proporcionado por Spring, que se implementa como DefaultUriBuilderFactory de forma predeterminada. El código y la implementación en RestTemplate son los siguientes:

private UriTemplateHandler uriTemplateHandler = new DefaultUriBuilderFactory();

 

A continuación, analizamos el método doExecute (), que se puede dividir aproximadamente en tres partes: crear una solicitud, ejecutar la solicitud y procesar el resultado de la solicitud. Primero analicemos cómo RestTemplate crea la solicitud.

protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
    ......
    ClientHttpResponse response = null;
    try {
        //获取HTTP请求客户端
	ClientHttpRequest request = createRequest(url, method);
        if (requestCallback != null) {
	    requestCallback.doWithRequest(request);
	}
        //发送请求
        response = request.execute();
        //处理结果
	handleResponse(url, method, response);
	return (responseExtractor != null ? responseExtractor.extractData(response) : null);
    }
    ......
}

RestTemplate se crea usando el método createRequest. El método createRequest es un método de HttpAccessor. En el diagrama de jerarquía de clases anterior, se puede ver que RestTemplate hereda HttpAccessor. Obtiene una fábrica de solicitudes a través de getRequestFactory () para crear una instancia de cliente de solicitud ClientHttpRequest.

protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
    //通过工厂类创建HTTP请求客户端
    ClientHttpRequest request = getRequestFactory().createRequest(url, method);
    return request;
}

Luego miramos cómo obtener la fábrica de solicitudes, getRequestFactory () se implementa en InterceptingHttpAccessor, hereda HttpAccessor, de hecho, lo que RestTemplate realmente integra es InterceptingHttpAccessor. El siguiente código crea una instancia de ClientHttpRequestFactory,

public ClientHttpRequestFactory getRequestFactory() {
    //获取请求拦截器ClientHttpRequestInterceptor实例
    List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
    //如果拦截器不为空,则通过默认的工厂和拦截器新构造一个InterceptingClientHttpRequestFactory实例
    if (!CollectionUtils.isEmpty(interceptors)) {
        ClientHttpRequestFactory factory = this.interceptingRequestFactory;
        if (factory == null) {
            factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
	    this.interceptingRequestFactory = factory;
	}
	return factory;
    }else {
        //否则返回默认的请求工厂实例
	return super.getRequestFactory();
    }
}

El código anterior crea principalmente una instancia de la clase de fábrica. Si el interceptor no está vacío, se crea una instancia de InterceptingClientHttpRequestFactory; de lo contrario, se devuelve una instancia predeterminada. La siguiente es la instancia predeterminada de ClientHttpRequestFactory proporcionada por Spring:

private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

 Además de la implementación de SimpleClientHttpRequestFactory, podemos configurar la instancia de fábrica a través de restTemplate.setRequestFactory (requestFactory). La siguiente es la implementación de ClientHttpRequestFactory:

 Aquí no se describe cómo crear una instancia de ClientHttpRequest. El núcleo es crear un cliente de una solicitud HTTP y agregar algunos parámetros requeridos por la solicitud. Nos enfocamos en cómo ejecutar el proceso de solicitud HTTP. Aquí hay una interfaz muy importante. El interceptor introducido: ClientHttpRequestInterceptor, interceptará la solicitud y ejecutará el interceptor antes de que se ejecute la solicitud. Aquí podemos hacer muchas cosas, como agregar encabezados de solicitud, cambiar la URL de la solicitud, autorización, etc. Algunos de los códigos son los siguientes:

public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
    //如果不为空执行拦截器,否则执行请求
    if (this.iterator.hasNext()) {
        ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
        return nextInterceptor.intercept(request, body, this);
    }
    //执行拦截器完毕之后发送请求
    .....
}

Debido a que ClientHttpRequestInterceptor se ejecuta de forma transversal, para garantizar la ejecución de la solicitud, debemos llamar al método de ejecución anterior en el ClientHttpRequestInterceptor personalizado. Cuando se ejecuta el interceptor, se ha pasado la instancia de InterceptingRequestExecution, por lo que podemos llamarlo directamente. A continuación, observamos un interceptor de autorización proporcionado por Spring, el código es el siguiente:

public class BasicAuthenticationInterceptor implements ClientHttpRequestInterceptor{
    private final String username;
    private final String password;
    @Nullable    
    private final Charset charset;
    //传入用户名和密码
    public BasicAuthenticationInterceptor(String username, String password){
        this(username, password, null);
    }
    public BasicAuthenticationInterceptor(String username, String password, @Nullable Charset charset){
        Assert.doesNotContain(username, ":", "Username must not contain a colon");
        this.username = username;
        this.password = password;
        this.charset = charset;
    }
  
  public ClientHttpResponse intercept(HttpRequest request, byte[] body,ClientHttpRequestExecution execution)throws IOException {
    HttpHeaders headers = request.getHeaders();
    //如果请求头包含Authorization设置BasicAuth
    if (!headers.containsKey("Authorization")) {
        headers.setBasicAuth(this.username, this.password, this.charset);
    }
    return execution.execute(request, body);
  }
}

El equilibrio de carga de Ribbon también se implementa mediante la implementación de ClientHttpRequestInterceptor. Si está interesado, puede consultar el contenido de la pila de tecnología de microservicio de columna Spring Cloud Netflix componente de equilibrio de carga de las aplicaciones avanzadas de Ribbon .

 

Supongo que te gusta

Origin blog.csdn.net/wk19920726/article/details/108754574
Recomendado
Clasificación