0
# Service Discovery
1
2
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.
3
4
## Capabilities
5
6
### SdkHttpService
7
8
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.
9
10
```java { .api }
11
/**
12
* Service Provider interface for HTTP implementations. The core uses ServiceLoader
13
* to find appropriate HTTP implementations on the classpath. HTTP implementations
14
* that wish to be discovered by the default HTTP provider chain should implement
15
* this interface and declare that implementation as a service in the
16
* META-INF/services/software.amazon.awssdk.http.SdkHttpService resource.
17
* This interface is simply a factory for SdkHttpClient.Builder.
18
* Implementations must be thread safe.
19
*/
20
@ThreadSafe
21
@SdkPublicApi
22
public interface SdkHttpService {
23
/**
24
* @return An SdkHttpClient.Builder capable of creating SdkHttpClient instances.
25
* This factory should be thread safe.
26
*/
27
SdkHttpClient.Builder createHttpClientBuilder();
28
}
29
```
30
31
**Usage Example:**
32
33
```java
34
// Implementation of SdkHttpService
35
public class MyHttpService implements SdkHttpService {
36
@Override
37
public SdkHttpClient.Builder createHttpClientBuilder() {
38
return new MyHttpClientBuilder();
39
}
40
}
41
42
// Builder implementation
43
public class MyHttpClientBuilder implements SdkHttpClient.Builder<MyHttpClientBuilder> {
44
private Duration connectionTimeout = Duration.ofSeconds(30);
45
private int maxConnections = 50;
46
47
public MyHttpClientBuilder connectionTimeout(Duration timeout) {
48
this.connectionTimeout = timeout;
49
return this;
50
}
51
52
public MyHttpClientBuilder maxConnections(int maxConnections) {
53
this.maxConnections = maxConnections;
54
return this;
55
}
56
57
@Override
58
public SdkHttpClient buildWithDefaults(AttributeMap serviceDefaults) {
59
// Apply service-specific defaults from AttributeMap
60
Duration finalTimeout = serviceDefaults.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT)
61
.orElse(connectionTimeout);
62
63
return new MyHttpClient(finalTimeout, maxConnections);
64
}
65
}
66
```
67
68
### SdkAsyncHttpService
69
70
Service Provider Interface for asynchronous HTTP client implementations. Similar to SdkHttpService but for async HTTP clients.
71
72
```java { .api }
73
/**
74
* Service Provider interface for asynchronous HTTP implementations.
75
* HTTP implementations that wish to be discovered by the default async HTTP provider
76
* chain should implement this interface and declare that implementation as a service
77
* in the META-INF/services/software.amazon.awssdk.http.async.SdkAsyncHttpService resource.
78
* Implementations must be thread safe.
79
*/
80
@ThreadSafe
81
@SdkPublicApi
82
public interface SdkAsyncHttpService {
83
/**
84
* @return An SdkAsyncHttpClient.Builder capable of creating SdkAsyncHttpClient instances.
85
* This factory should be thread safe.
86
*/
87
SdkAsyncHttpClient.Builder createAsyncHttpClientFactory();
88
}
89
```
90
91
**Usage Example:**
92
93
```java
94
// Implementation of SdkAsyncHttpService
95
public class MyAsyncHttpService implements SdkAsyncHttpService {
96
@Override
97
public SdkAsyncHttpClient.Builder createAsyncHttpClientFactory() {
98
return new MyAsyncHttpClientBuilder();
99
}
100
}
101
102
// Async builder implementation
103
public class MyAsyncHttpClientBuilder implements SdkAsyncHttpClient.Builder<MyAsyncHttpClientBuilder> {
104
private Duration connectionTimeout = Duration.ofSeconds(30);
105
private int maxConcurrency = 100;
106
private boolean http2Enabled = true;
107
108
public MyAsyncHttpClientBuilder connectionTimeout(Duration timeout) {
109
this.connectionTimeout = timeout;
110
return this;
111
}
112
113
public MyAsyncHttpClientBuilder maxConcurrency(int maxConcurrency) {
114
this.maxConcurrency = maxConcurrency;
115
return this;
116
}
117
118
public MyAsyncHttpClientBuilder http2Enabled(boolean enabled) {
119
this.http2Enabled = enabled;
120
return this;
121
}
122
123
@Override
124
public SdkAsyncHttpClient buildWithDefaults(AttributeMap serviceDefaults) {
125
// Apply service-specific defaults
126
Duration finalTimeout = serviceDefaults.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT)
127
.orElse(connectionTimeout);
128
Integer finalConcurrency = serviceDefaults.get(SdkHttpConfigurationOption.MAX_CONNECTIONS)
129
.orElse(maxConcurrency);
130
131
return new MyAsyncHttpClient(finalTimeout, finalConcurrency, http2Enabled);
132
}
133
}
134
```
135
136
## ServiceLoader Registration
137
138
### META-INF Services Files
139
140
To register your HTTP client implementation for automatic discovery, create the appropriate service files:
141
142
**For Synchronous HTTP Clients:**
143
144
Create file: `src/main/resources/META-INF/services/software.amazon.awssdk.http.SdkHttpService`
145
146
Content:
147
```
148
com.example.MyHttpService
149
```
150
151
**For Asynchronous HTTP Clients:**
152
153
Create file: `src/main/resources/META-INF/services/software.amazon.awssdk.http.async.SdkAsyncHttpService`
154
155
Content:
156
```
157
com.example.MyAsyncHttpService
158
```
159
160
### Multiple Implementations
161
162
You can register multiple implementations in the same service file:
163
164
```
165
com.example.MyHttpService
166
com.example.MyAlternativeHttpService
167
com.example.MySpecializedHttpService
168
```
169
170
The AWS SDK will discover all registered implementations and may use implementation-specific logic to select the most appropriate one.
171
172
## Service Discovery Process
173
174
### Loading Services
175
176
The AWS SDK uses `java.util.ServiceLoader` to discover HTTP client implementations:
177
178
```java
179
// SDK internal code (example of how services are loaded)
180
ServiceLoader<SdkHttpService> httpServices = ServiceLoader.load(SdkHttpService.class);
181
for (SdkHttpService service : httpServices) {
182
SdkHttpClient.Builder builder = service.createHttpClientBuilder();
183
// Use builder to create client with appropriate defaults
184
}
185
```
186
187
### Priority and Selection
188
189
When multiple HTTP client implementations are available:
190
1. The SDK may use internal heuristics to select the "best" implementation
191
2. Implementations can be explicitly selected via configuration
192
3. The order in META-INF services files may influence selection
193
194
### Classpath Requirements
195
196
For service discovery to work:
197
1. Your HTTP client implementation JAR must be on the classpath
198
2. The META-INF/services file must be properly formatted
199
3. The service implementation class must have a public no-argument constructor
200
201
## Configuration Integration
202
203
### Service Defaults
204
205
HTTP client services receive service-specific defaults via `AttributeMap`:
206
207
```java { .api }
208
/**
209
* Configuration options that may be passed to HTTP client builders
210
*/
211
public final class SdkHttpConfigurationOption {
212
// Common configuration options (examples)
213
public static final AttributeMap.Key<Duration> CONNECTION_TIMEOUT;
214
public static final AttributeMap.Key<Duration> SOCKET_TIMEOUT;
215
public static final AttributeMap.Key<Integer> MAX_CONNECTIONS;
216
public static final AttributeMap.Key<Boolean> REAP_IDLE_CONNECTIONS;
217
public static final AttributeMap.Key<Duration> CONNECTION_TIME_TO_LIVE;
218
public static final AttributeMap.Key<Duration> CONNECTION_MAX_IDLE_TIMEOUT;
219
public static final AttributeMap.Key<Boolean> USE_IDLE_CONNECTION_REAPER;
220
public static final AttributeMap.Key<ProxyConfiguration> PROXY_CONFIGURATION;
221
public static final AttributeMap.Key<Boolean> TRUST_ALL_CERTIFICATES;
222
}
223
```
224
225
**Usage in Builder:**
226
227
```java
228
@Override
229
public SdkHttpClient buildWithDefaults(AttributeMap serviceDefaults) {
230
MyHttpClientConfig.Builder configBuilder = MyHttpClientConfig.builder();
231
232
// Apply service defaults
233
serviceDefaults.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT)
234
.ifPresent(configBuilder::connectionTimeout);
235
236
serviceDefaults.get(SdkHttpConfigurationOption.MAX_CONNECTIONS)
237
.ifPresent(configBuilder::maxConnections);
238
239
serviceDefaults.get(SdkHttpConfigurationOption.PROXY_CONFIGURATION)
240
.ifPresent(configBuilder::proxyConfiguration);
241
242
return new MyHttpClient(configBuilder.build());
243
}
244
```
245
246
## Best Practices
247
248
### Implementation Guidelines
249
250
1. **Thread Safety**: All service implementations must be thread-safe
251
2. **Stateless Design**: Service implementations should be stateless factories
252
3. **Resource Management**: Builders should defer resource allocation until `build()` is called
253
4. **Configuration Validation**: Validate configuration parameters in builders
254
5. **Graceful Degradation**: Handle missing optional configuration gracefully
255
256
### Error Handling
257
258
```java
259
public class RobustHttpService implements SdkHttpService {
260
@Override
261
public SdkHttpClient.Builder createHttpClientBuilder() {
262
try {
263
return new MyHttpClientBuilder();
264
} catch (Exception e) {
265
// Log error but don't fail service loading
266
Logger.getLogger(getClass()).log(Level.WARNING,
267
"Failed to create HTTP client builder", e);
268
throw e; // Re-throw to let ServiceLoader handle
269
}
270
}
271
}
272
```
273
274
### Testing Service Discovery
275
276
```java
277
@Test
278
public void testServiceDiscovery() {
279
ServiceLoader<SdkHttpService> services = ServiceLoader.load(SdkHttpService.class);
280
281
assertThat(services).isNotEmpty();
282
283
for (SdkHttpService service : services) {
284
SdkHttpClient.Builder builder = service.createHttpClientBuilder();
285
assertThat(builder).isNotNull();
286
287
SdkHttpClient client = builder.build();
288
assertThat(client).isNotNull();
289
290
client.close();
291
}
292
}
293
```