类CallOptions

类CallOptions是新的RPC调用的运行时选项的集合。

类定义

package io.grpc;
@Immutable
public final class CallOptions {
}

注意@Immutable标签,这个CallOptions是不可变类。

属性和构造函数

CallOptions的代码注释中有讲到:虽然CallOptions是不可变类,但是它的属性并没有声明为final。这样可以在构造函数之外赋值,否则就需要在构造函数中给出长长的一个参数列表。

属性有下面5个,其中有几个声明为容许为null:

  private Long deadlineNanoTime;
  private Executor executor;

  @Nullable
  private String authority;

  @Nullable
  private RequestKey requestKey;

  @Nullable
  private String compressorName;

构造函数比较有意思,第二个版本的构造函数实现了复制功能,相当于创建了一个和给定实例数据完全相同的另一个对象实例:

  private CallOptions() {
  }

  private CallOptions(CallOptions other) {
    deadlineNanoTime = other.deadlineNanoTime;
    authority = other.authority;
    requestKey = other.requestKey;
    executor = other.executor;
    compressorName = other.compressorName;
  }

为了不使用传统的不可变类的实现方式(属性声明为final,构造函数中一一赋值),CallOptions中每次赋值都要使用上面的复制构造函数创建一个新的实例对象,然后返回新的实例对象(旧有实例就相当于抛弃了?):

public CallOptions withDeadlineNanoTime(@Nullable Long deadlineNanoTime) {
    CallOptions newOptions = new CallOptions(this);
    newOptions.deadlineNanoTime = deadlineNanoTime;
    return newOptions;
}

有个疑惑,按照上面的实现机制,如果CallOptions的使用者要创建一个有多次复制的CallOptions示例,就必须如下编码:

CallOptions callOptions = CallOptions.DEFAULT
    .withDeadlineNanoTime(***)
    .withAuthority(***)
    .withCompression(***)
    .withRequestKey(***)

这样实际会创建多次(取决于with()方法的调用次数)实例。不过从grpc的代码实现上看,每次只是在新建一个stub实例时才传入一个 CallOptions 实例,之后的每次调用都将重用这个 CallOptions 实例,所以实际上只是开始时创建多次实例,之后运行时就不再创建。

属性的详细含义

deadline / 最后期限

withDeadlineNanoTime() 返回新的一个CallOptions,最后期限为在给定的绝对值。这个绝对值以纳秒为单位,和每次 System.nanoTime() 的时间一致:

public CallOptions withDeadlineNanoTime(@Nullable Long deadlineNanoTime) {
    CallOptions newOptions = new CallOptions(this);
    newOptions.deadlineNanoTime = deadlineNanoTime;
    return newOptions;
}

withDeadlineAfter()方法返回一个最后期限为在给定期限之后的新的CallOptions, 可以看到实现的方式就是取当前的 System.nanoTime() 然后添加给定的期限:

public CallOptions withDeadlineAfter(long duration, TimeUnit unit) {
    return withDeadlineNanoTime(System.nanoTime() + unit.toNanos(duration));
}

executor

设置新的executor,用来覆盖 ManagedChannelBuilder.executor 指定的默认 executor 。

requestKey

用于基于亲和度(affinity-based)的路由的request key。

authority / 权限

覆盖 channel声明要连接到的 HTTP/2 的authority。这不是普遍安全的。覆盖容许高级用户为多个服务重用一个单一的channel,甚至这些服务在不同的域名上托管。这将假设服务器是虚拟托管了多个域名并被授权继续这样做。服务提供者极少作出这样的授权。此时,覆盖值没有安全认证,例如保证authority匹配服务器的TLS证书。

compressorName / 压缩器名称

设置为调用使用的压缩方式。压缩器必须是在 CompressorRegistry 已知的有效名称。