RestTemplateソースコード分析とClientHttpRequestInterceptorインターセプターの使用

Springを使用したことがある人は、RestTemplateの使用法をよく理解している必要があります。これはSpringが提供するHttpリクエストクライアントツールです。このブログでは、RestTemplateの使用法を紹介するのではなく、RestTemplateの呼び出しフローのみを分析します。RestTemplateの使用法を知りたい場合、Springの公式ドキュメントのSpringMVCセクションを確認できます。まず、RestTemplateクラスの階層図と提供されている呼び出しメソッドを見てみましょう。次のRestTemplateは、呼び出すための多くのAPIを提供し、その一部のみを以下に示します。

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));
}
......

上記のメソッドからわかるように、最終的にexecute()メソッドが呼び出されました。以下では、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);
}

execute()メソッドでは、URIは最初にUriTemplateHandlerを介して処理され、URIはURI変数を使用して拡張されます。以下はSpringによって提供されるUriTemplateHandlerであり、デフォルトでDefaultUriBuilderFactoryとして実装されます。RestTemplateのコードと実装は次のとおりです。

private UriTemplateHandler uriTemplateHandler = new DefaultUriBuilderFactory();

 

次に、doExecute()メソッドを見てみましょう。このメソッドは、リクエストの作成、リクエストの実行、リクエストの結果の処理という3つの部分に大別できます。まず、RestTemplateがリクエストを作成する方法を分析します。

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は、createRequestメソッドを使用して作成されます。createRequestメソッドはHttpAccessorのメソッドです。上記のクラス階層図から、RestTemplateはHttpAccessorを継承していることがわかります。これは、getRequestFactory()を介して要求ファクトリを取得し、要求クライアントClientHttpRequestインスタンスを作成します。

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

次に、リクエストファクトリを取得する方法を確認します。getRequestFactory()はInterceptingHttpAccessorに実装され、HttpAccessorを継承します。実際、RestTemplateが実際に統合するのはInterceptingHttpAccessorです。次のコードは、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();
    }
}

上記のコードは、主にファクトリクラスのインスタンスを作成します。インターセプタが空でない場合は、InterceptingClientHttpRequestFactoryインスタンスが作成されます。それ以外の場合は、デフォルトのインスタンスが返されます。Springが提供するデフォルトのClientHttpRequestFactoryインスタンスを次に示します。

private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

 SimpleClientHttpRequestFactoryの実装に加えて、restTemplate.setRequestFactory(requestFactory)を介してファクトリインスタンスを設定できます。ClientHttpRequestFactoryの実装は次のとおりです。

 ClientHttpRequestのインスタンスを作成する方法については、ここでは説明しません。コアは、HTTP要求のクライアントを作成し、要求に必要ないくつかのパラメーターを追加することです。ここでは、HTTP要求プロセスの実行方法に焦点を当てます。ここには非常に重要なインターフェイスがあります。導入されたインターセプター:ClientHttpRequestInterceptorは、リクエストをインターセプトし、リクエストが実行される前にインターセプターを実行します。ここでは、リクエストヘッダーの追加、リクエストURLの変更、承認など、さまざまなことができます。コードの一部は次のとおりです。

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

ClientHttpRequestInterceptorはトラバース実行であるため、リクエストを確実に実行するには、カスタムClientHttpRequestInterceptorで上記のexecuteメソッドを呼び出す必要があります。インターセプターが実行されると、InterceptingRequestExecutionインスタンスが渡されるため、直接呼び出すことができます。以下に、Springが提供する認証インターセプターを示します。コードは次のとおりです。

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);
  }
}

リボンの負荷分散は、ClientHttpRequestInterceptorを実装することによっても実装されます。興味がある場合は、列マイクロサービステクノロジスタックSpring CloudNetflix負荷分散コンポーネントのコンテンツを参照できます-リボンの高度なアプリケーション

 

おすすめ

転載: blog.csdn.net/wk19920726/article/details/108754574