【问题标题】:Java generics for setting up the default AWS clients用于设置默认 AWS 客户端的 Java 泛型
【发布时间】:2019-01-21 15:02:35
【问题描述】:

我希望能够为在我们的 AWS 后端创建的所有服务客户端强制执行不同的 httpClient 设置和 credentialsProvider。为此,我想使用 Java 泛型。

每当 somone 创建一个新的服务客户端时,我都会像这样使用它:

    S3Client s3client = setupAwsClient(S3Client.builder())
            .region(Region.EU_WEST_1)
            .build();

我不编译 setupAwsClient 的 impl 看起来像这样:

public <T extends AwsSyncClientBuilder<SdkSyncClientBuilder<...>, SdkClient> & BaseClientBuilder<S3ClientBuilder, SdkClient> T setupAwsClient(T client) {

    return client
            .credentialsProvider(credentialsProvider)
            .httpClient(awsBaseClient);
}

问题是接口太多了,我必须指定功能看起来一团糟。

我的问题是:在 AWS 开发工具包中的所有服务客户端之间强制执行某些设置的干净方法是什么?泛型是一个好的解决方案还是有更好的方法?

更新:
public <T extends AwsSyncClientBuilder<?,?> & AwsClientBuilder<?, ?>> T setup(T clientBuilder) {

}

尝试这个也不行。即使AwsClientBuilder 提供credentialsProviderAwsSyncClientBuilder 提供httpClient

【问题讨论】:

    标签: java amazon-web-services generics aws-sdk


    【解决方案1】:

    这就是你要找的吗?

    public <T extends AwsSyncClientBuilder<?, ?>> T setup(T clientBuilder) {
      /* Do stuff to client */
      return clientBuilder;
    }
    

    或者如果你想让setup方法调用build:

    public <C, T extends AwsSyncClientBuilder<?, C>> C setup(T clientBuilder) {
      /* Do stuff to client */
      return clientBuilder.build();
    }
    

    【讨论】:

    • 这里不提供credentialsProvider,只提供httpClient
    【解决方案2】:

    AwsSyncClientBuilder 将其自身或其任何子类型作为类型参数,但 SdkSyncClientBuilder 不是 AwsSyncClientBuilder 的子类型

    【讨论】:

      【解决方案3】:

      我认为您想多了,并让 AWS 开发工具包的复杂性过滤到您的应用程序代码中。

      首先,您真的需要异步客户端吗?与结合同步客户端和线程池相比,它们会给您带来什么好处?

      其次,您真正想要配置什么?看起来您想让调用代码配置区域而不是凭据提供程序?您还有什么要允许或控制的吗?

      我将使用的解决方案是一个简单的工厂方法,它采用您定义的配置对象:

      public static <T> T createClient(Class<T> clientKlass, MyConfigObject config)
      

      因此,根据您的示例,您可能会这样称呼:

      MyConfigObject config = new MyConfigObject().withRegion(Region.EU_WEST_1)
      S3Client s3Client = createClient(S3Client.class, config)
      

      createClient() 方法中,我可能会使用一个简单的 if-else 链来选择合适的构建器:

      if (clientKlass == S3Client.class) {
          S3ClientBuilder builder = S3Client.builder();
          applyConfig(builder, config);
          return builder.build();
      }
      

      如果您不喜欢 if-else 链,您可以使用反射来调用传递的客户端类上的 builder() 方法(以及结果上的 build() 方法)。

      applyConfig() 方法依赖于从AwsClientBuilder 派生的所有客户端,它提供了通用配置的方法:

      private static void applyConfig(AwsClientBuilder builder, MyConfiguration config) {
          if (config.getRegion() != null) {
              builder.region(config.getRegion());
          }
          builder.credentialsProvider(standardCredentials);
      }
      

      【讨论】:

      • 我没有使用异步客户端?我要控制的另一件事是使用的 httpClient,因为我必须在此设置代理才能让所有服务客户端正常工作。
      • 而 httpClient 我无法在您的 applyConfig 中设置。另一个问题是我必须知道用户可能要配置的所有内容并将其放入 MyConfiguration。我确实知道需要设置什么(示例中的 2 个字段),但是我不知道有人可能想要设置的所有字段。由于此处所述的原因,我不太喜欢您的解决方案。
      • 实际上,用户需要配置的东西很少。其中大部分将在应用程序级别进行配置。
      • 至于你不喜欢这个解决方案。我同意。但是,我认为,您至少应该注意使用对您有利的抽象。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-26
      • 2011-08-02
      • 2020-10-07
      • 1970-01-01
      • 2020-03-27
      相关资源
      最近更新 更多