CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-software-amazon-awssdk--http-client-spi

Service Provider Interface (SPI) for HTTP client implementations in the AWS SDK for Java v2

Overview
Eval results
Files

service-discovery.mddocs/

Service Discovery

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.

Capabilities

SdkHttpService

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);
    }
}

SdkAsyncHttpService

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);
    }
}

ServiceLoader Registration

META-INF Services Files

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.MyHttpService

For Asynchronous HTTP Clients:

Create file: src/main/resources/META-INF/services/software.amazon.awssdk.http.async.SdkAsyncHttpService

Content:

com.example.MyAsyncHttpService

Multiple Implementations

You can register multiple implementations in the same service file:

com.example.MyHttpService
com.example.MyAlternativeHttpService
com.example.MySpecializedHttpService

The AWS SDK will discover all registered implementations and may use implementation-specific logic to select the most appropriate one.

Service Discovery Process

Loading Services

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
}

Priority and Selection

When multiple HTTP client implementations are available:

  1. The SDK may use internal heuristics to select the "best" implementation
  2. Implementations can be explicitly selected via configuration
  3. The order in META-INF services files may influence selection

Classpath Requirements

For service discovery to work:

  1. Your HTTP client implementation JAR must be on the classpath
  2. The META-INF/services file must be properly formatted
  3. The service implementation class must have a public no-argument constructor

Configuration Integration

Service Defaults

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());
}

Best Practices

Implementation Guidelines

  1. Thread Safety: All service implementations must be thread-safe
  2. Stateless Design: Service implementations should be stateless factories
  3. Resource Management: Builders should defer resource allocation until build() is called
  4. Configuration Validation: Validate configuration parameters in builders
  5. Graceful Degradation: Handle missing optional configuration gracefully

Error Handling

public 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
        }
    }
}

Testing Service Discovery

@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

docs

content-streaming.md

http-clients.md

http-messages.md

index.md

metrics.md

service-discovery.md

tls-configuration.md

tile.json