static <T extends Response> RetryConfigMapping<T> of(
            BiFunction<? super ClientRequestContext, Request, String> keyFactory,
            BiFunction<? super ClientRequestContext, Request, RetryConfig<T>> retryConfigFactory) {
        return new KeyedRetryConfigMapping<>(keyFactory, retryConfigFactory);
    }
Creates a {@link RetryConfigMapping} that maps keys created by {@code keyFactory} to
{@link RetryConfig}s created by {@code retryConfigFactory}.
The key produced by {@code keyFactory} is used to cache the corresponding {@link RetryConfig} produced
by {@code retryConfigFactory}. So if {@code keyFactory} produces a key that has been seen before,
the cached {@link RetryConfig} is used, and the output of {@code retryConfigFactory} is ignored.
Example:
<pre> {@code
BiFunction<ClientRequestContext, Request, String> keyFactory =
    (ctx, req) -> ctx.endpoint().host();
BiFunction<ClientRequestContext, Request, RetryConfig<HttpResponse>> configFactory = (ctx, req) -> {
    if (ctx.endpoint().host().equals("host1")) {
        return RetryConfig.<HttpResponse>builder(RetryRule.onException()).maxTotalAttempts(2).build();
    } else if (ctx.endpoint().host().equals("host2")) {
        return RetryConfig.<HttpResponse>builder(RetryRule.onException()).maxTotalAttempts(4).build();
    } else {
        return RetryConfig.<HttpResponse>builder(RetryRule.onException()).maxTotalAttempts(1).build();
    }
};
RetryConfigMapping mapping = RetryConfigMapping.of(keyFactory, configFactory);
} </pre>
core/src/main/java/com/linecorp/armeria/client/retry/RetryConfigMapping.java