SpringMVC架构代码解析之requestExecutor

原创 码农  2019-12-27 11:00:03  阅读 457 次 评论 0 条

源码解析


SpringMVC架构代码解析之requestExecutor SpringMVC架构代码解析之requestExecutor 架构


org.springframework.remoting.httpinvoker.HttpInvokerRequestExecutor

用于实际执行HTTP调用程序请求的策略接口。由HttpInvokerClientInterceptor及其子类HttpInvokerProxyFactoryBean使用。提供了两个开箱即用的实现:SimpleHttpInvokerRequestExecutor:使用JDK工具执行POST请求,不支持HTTP身份验证或高级配置选项。HttpComponentsHttpInvokerRequestExecutor:使用Apache的Commons HttpClient执行POST请求,允许使用预配置的HttpClient实例(可能使用身份验证、HTTP连接池等)。

RemoteInvocationResult executeRequest(HttpInvokerClientConfiguration config, RemoteInvocation invocation)
      throws Exception;

执行请求。


org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor

HttpInvokerRequestExecutor接口的抽象基础实现。预实现RemoteInvocation对象的序列化和RemoteInvocationResults对象的反序列化。

  @Override
  public final RemoteInvocationResult executeRequest(
      HttpInvokerClientConfiguration config, RemoteInvocation invocation) throws Exception {

    ByteArrayOutputStream baos = getByteArrayOutputStream(invocation);
    if (logger.isDebugEnabled()) {
      logger.debug("Sending HTTP invoker request for service at [" + config.getServiceUrl() +
          "], with size " + baos.size());
    }
    return doExecuteRequest(config, baos);
  }

执行request,这里是模板方法实现。创建输出流写入RemoteInvocation,org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor#doExecuteRequest 执行请求发送给定的序列化远程调用。实现通常调用readRemoteInvocationResult来反序列化返回的RemoteInvocationResult对象。需要子类实现这个模板方法。org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor#writeRemoteInvocation

将给定的RemoteInvocation序列化到给定的OutputStream。默认实现使decorateOutputStream有机会首先修饰流(例如,用于自定义加密或压缩)。为最终流创建ObjectOutputStream并调用doWriteRemoteInvocation来实际编写对象。可以为调用的自定义序列化重写。

protected void writeRemoteInvocation(RemoteInvocation invocation, OutputStream os) throws IOException {
    ObjectOutputStream oos = new ObjectOutputStream(decorateOutputStream(os));
    try {
      doWriteRemoteInvocation(invocation, oos);
    }
    finally {
      oos.close();
    }
  }

将给定的调用对象实际写入给定的ObjectOutputStream。默认实现只调用writeObject。可以覆盖自定义包装器对象的序列化,而不是普通调用,例如支持加密的持有者。

protected void doWriteRemoteInvocation(RemoteInvocation invocation, ObjectOutputStream oos) throws IOException {
    oos.writeObject(invocation);
  }

org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor#decorateOutputStream 返回OutputStream以用于编写远程调用,潜在地修饰给定的原始OutputStream。默认实现按原样返回给定的流。可以覆盖,例如,用于自定义加密或压缩。

protected OutputStream decorateOutputStream(OutputStream os) throws IOException {
    return os;
  }

org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor#readRemoteInvocationResult 从给定的InputStream反序列化RemoteInvocationResult对象。为decorateInputStream提供了首先修饰流的机会(例如,用于自定义加密或压缩)。通过createObjectInputStream创建一个ObjectInputStream,并调用doReadRemoteInvocationResult来实际读取该对象。可以为调用的自定义序列化重写。

    protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, String codebaseUrl)
      throws IOException, ClassNotFoundException {

    ObjectInputStream ois = createObjectInputStream(decorateInputStream(is), codebaseUrl);
    try {
      return doReadRemoteInvocationResult(ois);
    }
    finally {
      ois.close();
    }
  }

org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor#doReadRemoteInvocationResult 从给定的ObjectInputStream执行调用对象的实际读取。默认实现只调用readObject。可以覆盖自定义包装器对象的反序列化,而不是普通调用,例如支持加密的持有者。

protected RemoteInvocationResult doReadRemoteInvocationResult(ObjectInputStream ois)
      throws IOException, ClassNotFoundException {

    Object obj = ois.readObject();
    if (!(obj instanceof RemoteInvocationResult)) {
      throw new RemoteException("Deserialized object needs to be assignable to type [" +
          RemoteInvocationResult.class.getName() + "]: " + ClassUtils.getDescriptiveType(obj));
    }
    return (RemoteInvocationResult) obj;
  }

org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor#decorateInputStream 返回用于读取远程调用结果的InputStream,潜在地修饰给定的原始InputStream。默认实现按原样返回给定的流。可以覆盖,例如,用于自定义加密或压缩。

protected InputStream decorateInputStream(InputStream is) throws IOException {
    return is;
  }

org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor HttpInvokerRequestExecutor实现,它使用标准Java工具来执行POST请求,不支持HTTP身份验证或高级配置选项。设计用于简单的子类化,定制特定的模板方法。但是,考虑HttpComponentsHttpInvokerRequestExecutor以获得更复杂的需求:标准HttpURLConnection类的功能相当有限。

private int connectTimeout = -1;

connectTimeout

设置底层URLConnection的连接超时(单位为毫秒)。超时值0指定无限超时。Default是系统的默认超时。

private int readTimeout = -1;

readTimeout

  @Override
  protected RemoteInvocationResult doExecuteRequest(
      HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
      throws IOException, ClassNotFoundException {

//    创建HttpURLConnection
    HttpURLConnection con = openConnection(config);
//    预处理HttpURLConnection
    prepareConnection(con, baos.size());
//    写requestBody
    writeRequestBody(config, con, baos);
//    验证响应
    validateResponse(config, con);
//    读取响应信息
    InputStream responseBody = readResponseBody(config, con);

//    读取执行结果
    return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
  }

通过HttpURLConnection执行请求返回结果。


org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor#openConnection 根据服务url创建HttpURLConnection

protected HttpURLConnection openConnection(HttpInvokerClientConfiguration config) throws IOException {
    URLConnection con = new URL(config.getServiceUrl()).openConnection();
    if (!(con instanceof HttpURLConnection)) {
      throw new IOException(
          "Service URL [" + config.getServiceUrl() + "] does not resolve to an HTTP connection");
    }
    return (HttpURLConnection) con;
  }

准备给定的HTTP连接。默认实现将POST指定为方法,将“application/x-java-serialize -object”指定为“content - type”报头,将给定的内容长度指定为“content - length”报头org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor#prepareConnection

protected void prepareConnection(HttpURLConnection connection, int contentLength) throws IOException {
//    设置连接超时参数
    if (this.connectTimeout >= 0) {
      connection.setConnectTimeout(this.connectTimeout);
    }
//    设置读取超时参数
    if (this.readTimeout >= 0) {
      connection.setReadTimeout(this.readTimeout);
    }

    connection.setDoOutput(true);
//    设置http请求方式为post
    connection.setRequestMethod(HTTP_METHOD_POST);
//    设置contentType为application/x-java-serialized-object
    connection.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, getContentType());
//    设置Content-Length
    connection.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, Integer.toString(contentLength));

    LocaleContext localeContext = LocaleContextHolder.getLocaleContext();
    if (localeContext != null) {
      Locale locale = localeContext.getLocale();
      if (locale != null) {
        connection.setRequestProperty(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale));
      }
    }

//    设置Accept-Encoding为gzip
    if (isAcceptGzipEncoding()) {
      connection.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
    }
  }

org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor#writeRequestBody 写入请求体

protected void writeRequestBody(
      HttpInvokerClientConfiguration config, HttpURLConnection con, ByteArrayOutputStream baos)
      throws IOException {

    baos.writeTo(con.getOutputStream());
  }

org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor#validateResponse 设置响应

protected void validateResponse(HttpInvokerClientConfiguration config, HttpURLConnection con)
      throws IOException {

    if (con.getResponseCode() >= 300) {
      throw new IOException(
          "Did not receive successful HTTP response: status code = " + con.getResponseCode() +
          ", status message = [" + con.getResponseMessage() + "]");
    }
  }

org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor#readResponseBody 读取响应体

protected InputStream readResponseBody(HttpInvokerClientConfiguration config, HttpURLConnection con)
      throws IOException {

//    判断请求头Content-Encoding是不是gzip
    if (isGzipResponse(con)) {
      // GZIP response found - need to unzip.
      return new GZIPInputStream(con.getInputStream());
    }
    else {
      // Plain response found.
      return con.getInputStream();
    }
  }

org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor#readRemoteInvocationResult 从给定的InputStream反序列化RemoteInvocationResult对象。为decorateInputStream提供了首先修饰流的机会(例如,用于自定义加密或压缩)。通过createObjectInputStream创建一个ObjectInputStream,并调用doReadRemoteInvocationResult来实际读取该对象。可以为调用的自定义序列化重写。

protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, String codebaseUrl)
      throws IOException, ClassNotFoundException {

    ObjectInputStream ois = createObjectInputStream(decorateInputStream(is), codebaseUrl);
    try {
      return doReadRemoteInvocationResult(ois);
    }
    finally {
      ois.close();
    }
  }

org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor#doReadRemoteInvocationResult 从给定的ObjectInputStream执行调用对象的实际读取。默认实现只调用readObject。可以覆盖自定义包装器对象的反序列化,而不是普通调用,例如支持加密的持有者。

  protected RemoteInvocationResult doReadRemoteInvocationResult(ObjectInputStream ois)
      throws IOException, ClassNotFoundException {

    Object obj = ois.readObject();
    if (!(obj instanceof RemoteInvocationResult)) {
      throw new RemoteException("Deserialized object needs to be assignable to type [" +
          RemoteInvocationResult.class.getName() + "]: " + ClassUtils.getDescriptiveType(obj));
    }
    return (RemoteInvocationResult) obj;
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor 使用Apache HttpComponents HttpClient执行POST请求的HttpInvokerRequestExecutor实现。允许使用预先配置的HttpClient实例,可能包括身份验证、HTTP连接池等。还设计为易于子类化,提供特定的模板方法。从Spring 4.1开始,这个请求执行器需要Apache HttpComponents 4.3或更高版本。

private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 100;

默认最大连接数

private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;

默认每个route最大连接数

private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000);

默认读超时参数

private HttpClient httpClient;

httpClient

private RequestConfig requestConfig;

requestConfig

public HttpComponentsHttpInvokerRequestExecutor() {
    this(createDefaultHttpClient(), RequestConfig.custom()
        .setSocketTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS).build());
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#createDefaultHttpClient

private static HttpClient createDefaultHttpClient() {
    Registry<ConnectionSocketFactory> schemeRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.getSocketFactory())
        .register("https", SSLConnectionSocketFactory.getSocketFactory())
        .build();

    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(schemeRegistry);
    connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);
    connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);

    return HttpClientBuilder.create().setConnectionManager(connectionManager).build();
  }

创建httpClient

public void setConnectTimeout(int timeout) {
    Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
    this.requestConfig = cloneRequestConfig().setConnectTimeout(timeout).build();
    setLegacyConnectionTimeout(getHttpClient(), timeout);
  }

设置httpClient连接超时参数

public void setConnectionRequestTimeout(int connectionRequestTimeout) {
    this.requestConfig = cloneRequestConfig().setConnectionRequestTimeout(connectionRequestTimeout).build();
  }

设置连接请求超时参数

public void setReadTimeout(int timeout) {
    Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
    this.requestConfig = cloneRequestConfig().setSocketTimeout(timeout).build();
    setLegacySocketTimeout(getHttpClient(), timeout);
  }

设置读取超时参数

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#doExecuteRequest 通过httpClient执行request

@Override
  protected RemoteInvocationResult doExecuteRequest(
      HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
      throws IOException, ClassNotFoundException {

//    创建httpPost
    HttpPost postMethod = createHttpPost(config);
//    设置请求体
    setRequestBody(config, postMethod, baos);
    try {
//      执行httpPost请求返回httpResponse
      HttpResponse response = executeHttpPost(config, getHttpClient(), postMethod);
//      验证响应
      validateResponse(config, response);
//      获取请求体
      InputStream responseBody = getResponseBody(config, response);
//      读取执行结果
      return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
    }
    finally {
//      释放连接
      postMethod.releaseConnection();
    }
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#createHttpPost 为给定的配置创建HttpPost。默认实现创建一个标准HttpPost,其“application/x-java-serialize -object”作为“Content-Type”报头。

protected HttpPost createHttpPost(HttpInvokerClientConfiguration config) throws IOException {
//    根据serviceUrl创建HttpPost
    HttpPost httpPost = new HttpPost(config.getServiceUrl());

//    创建requestConfig
    RequestConfig requestConfig = createRequestConfig(config);
    if (requestConfig != null) {
      httpPost.setConfig(requestConfig);
    }

    LocaleContext localeContext = LocaleContextHolder.getLocaleContext();
    if (localeContext != null) {
      Locale locale = localeContext.getLocale();
      if (locale != null) {
        httpPost.addHeader(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale));
      }
    }

//    设置请求头Accept-Encoding为gzip
    if (isAcceptGzipEncoding()) {
      httpPost.addHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
    }

    return httpPost;
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#createRequestConfig 为给定的配置创建RequestConfig。可以返回null,以指示不应该设置自定义请求配置,并且应该使用HttpClient的默认值。默认实现尝试将客户机的默认值与实例的本地自定义(如果有的话)合并。

protected RequestConfig createRequestConfig(HttpInvokerClientConfiguration config) {
    HttpClient client = getHttpClient();
    if (client instanceof Configurable) {
      RequestConfig clientRequestConfig = ((Configurable) client).getConfig();
      return mergeRequestConfig(clientRequestConfig);
    }
    return this.requestConfig;
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#mergeRequestConfig

private RequestConfig mergeRequestConfig(RequestConfig defaultRequestConfig) {
    if (this.requestConfig == null) {  // nothing to merge
      return defaultRequestConfig;
    }

    RequestConfig.Builder builder = RequestConfig.copy(defaultRequestConfig);
    int connectTimeout = this.requestConfig.getConnectTimeout();
    if (connectTimeout >= 0) {
      builder.setConnectTimeout(connectTimeout);
    }
    int connectionRequestTimeout = this.requestConfig.getConnectionRequestTimeout();
    if (connectionRequestTimeout >= 0) {
      builder.setConnectionRequestTimeout(connectionRequestTimeout);
    }
    int socketTimeout = this.requestConfig.getSocketTimeout();
    if (socketTimeout >= 0) {
      builder.setSocketTimeout(socketTimeout);
    }
    return builder.build();
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#setRequestBody 将给定的序列化远程调用设置为请求体。默认实现只是将序列化的调用设置为HttpPost的请求体。例如,可以重写它来编写特定的编码并可能设置适当的HTTP请求头。

protected void setRequestBody(
      HttpInvokerClientConfiguration config, HttpPost httpPost, ByteArrayOutputStream baos)
      throws IOException {

    ByteArrayEntity entity = new ByteArrayEntity(baos.toByteArray());
    entity.setContentType(getContentType());
    httpPost.setEntity(entity);
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#executeHttpPost 执行httpPost请求

protected HttpResponse executeHttpPost(
      HttpInvokerClientConfiguration config, HttpClient httpClient, HttpPost httpPost)
      throws IOException {

    return httpClient.execute(httpPost);
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#validateResponse 验证响应

protected void validateResponse(HttpInvokerClientConfiguration config, HttpResponse response)
      throws IOException {

    StatusLine status = response.getStatusLine();
    if (status.getStatusCode() >= 300) {
      throw new NoHttpResponseException(
          "Did not receive successful HTTP response: status code = " + status.getStatusCode() +
          ", status message = [" + status.getReasonPhrase() + "]");
    }
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#getResponseBody 获取响应体

protected InputStream getResponseBody(HttpInvokerClientConfiguration config, HttpResponse httpResponse)
      throws IOException {

    if (isGzipResponse(httpResponse)) {
      return new GZIPInputStream(httpResponse.getEntity().getContent());
    }
    else {
      return httpResponse.getEntity().getContent();
    }
  }

org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#isGzipResponse 判断请求头Content-Encoding是不是gzip

protected boolean isGzipResponse(HttpResponse httpResponse) {
    Header encodingHeader = httpResponse.getFirstHeader(HTTP_HEADER_CONTENT_ENCODING);
    return (encodingHeader != null && encodingHeader.getValue() != null &&
        encodingHeader.getValue().toLowerCase().contains(ENCODING_GZIP));
  }


说在最后

本次解析仅代表个人观点,仅供参考。


本文地址:https://www.itcodeit.com/post/32.html
版权声明:本文为原创文章,版权归 码农 所有,欢迎分享本文,转载请保留出处!

发表评论


表情

还没有留言,还不快点抢沙发?