Service Provider Interface (SPI) for HTTP client implementations in the AWS SDK for Java v2
ServiceLoader-based SPI interfaces that enable automatic discovery and instantiation of HTTP client implementations on the classpath. This follows standard Java service provider patterns to allow HTTP client implementations to be discovered and loaded dynamically.
Service Provider Interface for synchronous HTTP client implementations. HTTP client libraries implement this interface and register it via ServiceLoader to be automatically discovered by the AWS SDK.
/**
* Service Provider interface for HTTP implementations. The core uses ServiceLoader
* to find appropriate HTTP implementations on the classpath. HTTP implementations
* that wish to be discovered by the default HTTP provider chain should implement
* this interface and declare that implementation as a service in the
* META-INF/services/software.amazon.awssdk.http.SdkHttpService resource.
* This interface is simply a factory for SdkHttpClient.Builder.
* Implementations must be thread safe.
*/
@ThreadSafe
@SdkPublicApi
public interface SdkHttpService {
/**
* @return An SdkHttpClient.Builder capable of creating SdkHttpClient instances.
* This factory should be thread safe.
*/
SdkHttpClient.Builder createHttpClientBuilder();
}Usage Example:
// Implementation of SdkHttpService
public class MyHttpService implements SdkHttpService {
@Override
public SdkHttpClient.Builder createHttpClientBuilder() {
return new MyHttpClientBuilder();
}
}
// Builder implementation
public class MyHttpClientBuilder implements SdkHttpClient.Builder<MyHttpClientBuilder> {
private Duration connectionTimeout = Duration.ofSeconds(30);
private int maxConnections = 50;
public MyHttpClientBuilder connectionTimeout(Duration timeout) {
this.connectionTimeout = timeout;
return this;
}
public MyHttpClientBuilder maxConnections(int maxConnections) {
this.maxConnections = maxConnections;
return this;
}
@Override
public SdkHttpClient buildWithDefaults(AttributeMap serviceDefaults) {
// Apply service-specific defaults from AttributeMap
Duration finalTimeout = serviceDefaults.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT)
.orElse(connectionTimeout);
return new MyHttpClient(finalTimeout, maxConnections);
}
}Service Provider Interface for asynchronous HTTP client implementations. Similar to SdkHttpService but for async HTTP clients.
/**
* Service Provider interface for asynchronous HTTP implementations.
* HTTP implementations that wish to be discovered by the default async HTTP provider
* chain should implement this interface and declare that implementation as a service
* in the META-INF/services/software.amazon.awssdk.http.async.SdkAsyncHttpService resource.
* Implementations must be thread safe.
*/
@ThreadSafe
@SdkPublicApi
public interface SdkAsyncHttpService {
/**
* @return An SdkAsyncHttpClient.Builder capable of creating SdkAsyncHttpClient instances.
* This factory should be thread safe.
*/
SdkAsyncHttpClient.Builder createAsyncHttpClientFactory();
}Usage Example:
// Implementation of SdkAsyncHttpService
public class MyAsyncHttpService implements SdkAsyncHttpService {
@Override
public SdkAsyncHttpClient.Builder createAsyncHttpClientFactory() {
return new MyAsyncHttpClientBuilder();
}
}
// Async builder implementation
public class MyAsyncHttpClientBuilder implements SdkAsyncHttpClient.Builder<MyAsyncHttpClientBuilder> {
private Duration connectionTimeout = Duration.ofSeconds(30);
private int maxConcurrency = 100;
private boolean http2Enabled = true;
public MyAsyncHttpClientBuilder connectionTimeout(Duration timeout) {
this.connectionTimeout = timeout;
return this;
}
public MyAsyncHttpClientBuilder maxConcurrency(int maxConcurrency) {
this.maxConcurrency = maxConcurrency;
return this;
}
public MyAsyncHttpClientBuilder http2Enabled(boolean enabled) {
this.http2Enabled = enabled;
return this;
}
@Override
public SdkAsyncHttpClient buildWithDefaults(AttributeMap serviceDefaults) {
// Apply service-specific defaults
Duration finalTimeout = serviceDefaults.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT)
.orElse(connectionTimeout);
Integer finalConcurrency = serviceDefaults.get(SdkHttpConfigurationOption.MAX_CONNECTIONS)
.orElse(maxConcurrency);
return new MyAsyncHttpClient(finalTimeout, finalConcurrency, http2Enabled);
}
}To register your HTTP client implementation for automatic discovery, create the appropriate service files:
For Synchronous HTTP Clients:
Create file: src/main/resources/META-INF/services/software.amazon.awssdk.http.SdkHttpService
Content:
com.example.MyHttpServiceFor Asynchronous HTTP Clients:
Create file: src/main/resources/META-INF/services/software.amazon.awssdk.http.async.SdkAsyncHttpService
Content:
com.example.MyAsyncHttpServiceYou can register multiple implementations in the same service file:
com.example.MyHttpService
com.example.MyAlternativeHttpService
com.example.MySpecializedHttpServiceThe AWS SDK will discover all registered implementations and may use implementation-specific logic to select the most appropriate one.
The AWS SDK uses java.util.ServiceLoader to discover HTTP client implementations:
// SDK internal code (example of how services are loaded)
ServiceLoader<SdkHttpService> httpServices = ServiceLoader.load(SdkHttpService.class);
for (SdkHttpService service : httpServices) {
SdkHttpClient.Builder builder = service.createHttpClientBuilder();
// Use builder to create client with appropriate defaults
}When multiple HTTP client implementations are available:
For service discovery to work:
HTTP client services receive service-specific defaults via AttributeMap:
/**
* Configuration options that may be passed to HTTP client builders
*/
public final class SdkHttpConfigurationOption {
// Common configuration options (examples)
public static final AttributeMap.Key<Duration> CONNECTION_TIMEOUT;
public static final AttributeMap.Key<Duration> SOCKET_TIMEOUT;
public static final AttributeMap.Key<Integer> MAX_CONNECTIONS;
public static final AttributeMap.Key<Boolean> REAP_IDLE_CONNECTIONS;
public static final AttributeMap.Key<Duration> CONNECTION_TIME_TO_LIVE;
public static final AttributeMap.Key<Duration> CONNECTION_MAX_IDLE_TIMEOUT;
public static final AttributeMap.Key<Boolean> USE_IDLE_CONNECTION_REAPER;
public static final AttributeMap.Key<ProxyConfiguration> PROXY_CONFIGURATION;
public static final AttributeMap.Key<Boolean> TRUST_ALL_CERTIFICATES;
}Usage in Builder:
@Override
public SdkHttpClient buildWithDefaults(AttributeMap serviceDefaults) {
MyHttpClientConfig.Builder configBuilder = MyHttpClientConfig.builder();
// Apply service defaults
serviceDefaults.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT)
.ifPresent(configBuilder::connectionTimeout);
serviceDefaults.get(SdkHttpConfigurationOption.MAX_CONNECTIONS)
.ifPresent(configBuilder::maxConnections);
serviceDefaults.get(SdkHttpConfigurationOption.PROXY_CONFIGURATION)
.ifPresent(configBuilder::proxyConfiguration);
return new MyHttpClient(configBuilder.build());
}build() is calledpublic class RobustHttpService implements SdkHttpService {
@Override
public SdkHttpClient.Builder createHttpClientBuilder() {
try {
return new MyHttpClientBuilder();
} catch (Exception e) {
// Log error but don't fail service loading
Logger.getLogger(getClass()).log(Level.WARNING,
"Failed to create HTTP client builder", e);
throw e; // Re-throw to let ServiceLoader handle
}
}
}@Test
public void testServiceDiscovery() {
ServiceLoader<SdkHttpService> services = ServiceLoader.load(SdkHttpService.class);
assertThat(services).isNotEmpty();
for (SdkHttpService service : services) {
SdkHttpClient.Builder builder = service.createHttpClientBuilder();
assertThat(builder).isNotNull();
SdkHttpClient client = builder.build();
assertThat(client).isNotNull();
client.close();
}
}Install with Tessl CLI
npx tessl i tessl/maven-software-amazon-awssdk--http-client-spi