@@ -1130,3 +1130,139 @@ For more details and options such as suppressing error status codes, see the ref
1130
1130
documentation for each client, as well as the Javadoc of `defaultStatusHandler` in
1131
1131
`RestClient.Builder` or `WebClient.Builder`, and the `setErrorHandler` of `RestTemplate`.
1132
1132
1133
+
1134
+
1135
+ [[rest-http-interface-group-config]]
1136
+ === HTTP Interface Groups
1137
+
1138
+ It's trivial to create client proxies with `HttpServiceProxyFactory`, but to have them
1139
+ declared as beans leads to repetitive configuration. You may also have multiple
1140
+ target hosts, and therefore multiple clients to configure, and even more client proxy
1141
+ beans to create.
1142
+
1143
+ To make it easier to work with interface clients at scale the Spring Framework provides
1144
+ dedicated configuration support. It lets applications focus on identifying HTTP Services
1145
+ by group, and customizing the client for each group, while the framework transparently
1146
+ creates a registry of client proxies, and declares each proxy as a bean.
1147
+
1148
+ An HTTP Service group is simply a set of interfaces that share the same client setup and
1149
+ `HttpServiceProxyFactory` instance to create proxies. Typically, that means one group per
1150
+ host, but you can have more than one group for the same target host in case the
1151
+ underlying client needs to be configured differently.
1152
+
1153
+ One way to declare HTTP Service groups is via `@ImportHttpServices` annotations in
1154
+ `@Configuration` classes as shown below:
1155
+
1156
+ [source,java,indent=0,subs="verbatim,quotes"]
1157
+ ----
1158
+ @Configuration
1159
+ @ImportHttpServices(group = "echo", types = {EchoServieA.class, EchoServiceB.class}) // <1>
1160
+ @ImportHttpServices(group = "greeting", basePackageClasses = GreetServiceA.class) // <2>
1161
+ public class ClientConfig {
1162
+ }
1163
+
1164
+ ----
1165
+ <1> Manually list interfaces for group "echo"
1166
+ <2> Detect interfaces for group "greeting" under a base package
1167
+
1168
+ It is also possible to declare groups programmatically by creating an HTTP Service
1169
+ registrar and then importing it:
1170
+
1171
+ [source,java,indent=0,subs="verbatim,quotes"]
1172
+ ----
1173
+ public class MyHttpServiceRegistrar extends AbstractHttpServiceRegistrar { // <1>
1174
+
1175
+ @Override
1176
+ protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata metadata) {
1177
+ registry.forGroup("echo").register(EchoServiceA.class, EchoServiceB.class); // <2>
1178
+ registry.forGroup("greeting").detectInBasePackages(GreetServiceA.class); // <3>
1179
+ }
1180
+ }
1181
+
1182
+ @Configuration
1183
+ @Import(MyHttpServiceRegistrar.class) // <4>
1184
+ public class ClientConfig {
1185
+ }
1186
+
1187
+ ----
1188
+ <1> Create extension class of `AbstractHttpServiceRegistrar`
1189
+ <2> Manually list interfaces for group "echo"
1190
+ <3> Detect interfaces for group "greeting" under a base package
1191
+ <4> Import the registrar
1192
+
1193
+ TIP: You can mix and match `@ImportHttpService` annotations with programmatic registrars,
1194
+ and you can spread the imports across multiple configuration classes. All imports
1195
+ contribute collaboratively the same, shared `HttpServiceProxyRegistry` instance.
1196
+
1197
+ Once HTTP Service groups are declared, add an `HttpServiceGroupConfigurer` bean to
1198
+ customize the client for each group. For example:
1199
+
1200
+ [source,java,indent=0,subs="verbatim,quotes"]
1201
+ ----
1202
+ @Configuration
1203
+ @ImportHttpServices(group = "echo", types = {EchoServiceA.class, EchoServiceB.class})
1204
+ @ImportHttpServices(group = "greeting", basePackageClasses = GreetServiceA.class)
1205
+ public class ClientConfig {
1206
+
1207
+ @Bean
1208
+ public RestClientHttpServiceGroupConfigurer groupConfigurer() {
1209
+ return groups -> {
1210
+ // configure client for group "echo"
1211
+ groups.filterByName("echo").forEachClient((group, clientBuilder) -> ...);
1212
+
1213
+ // configure the clients for all groups
1214
+ groups.forEachClient((group, clientBuilder) -> ...);
1215
+
1216
+ // configure client and proxy factory for each group
1217
+ groups.forEachGroup((group, clientBuilder, factoryBuilder) -> ...);
1218
+ };
1219
+ }
1220
+ }
1221
+ ----
1222
+
1223
+ TIP: Spring Boot uses an `HttpServiceGroupConfigurer` to add support for client properties
1224
+ by HTTP Service group, Spring Security to add OAuth support, and Spring Cloud to add load
1225
+ balancing.
1226
+
1227
+ As a result of the above, each client proxy is available as a bean that you can
1228
+ conveniently autowire by type:
1229
+
1230
+ [source,java,indent=0,subs="verbatim,quotes"]
1231
+ ----
1232
+ @RestController
1233
+ public class EchoController {
1234
+
1235
+ private final EchoService echoService;
1236
+
1237
+ public EchoController(EchoService echoService) {
1238
+ this.echoService = echoService;
1239
+ }
1240
+
1241
+ // ...
1242
+ }
1243
+ ----
1244
+
1245
+ However, if there are multiple client proxies of the same type, e.g. the same interface
1246
+ in multiple groups, then there is no unique bean of that type, and you cannot autowire by
1247
+ type only. For such cases, you can work directly with the `HttpServiceProxyRegistry` that
1248
+ holds all proxies, and obtain the ones you need by group:
1249
+
1250
+ [source,java,indent=0,subs="verbatim,quotes"]
1251
+ ----
1252
+ @RestController
1253
+ public class EchoController {
1254
+
1255
+ private final EchoService echoService1;
1256
+
1257
+ private final EchoService echoService2;
1258
+
1259
+ public EchoController(HttpServiceProxyRegistry registry) {
1260
+ this.echoService1 = registry.getClient("echo1", EchoService.class); // <1>
1261
+ this.echoService2 = registry.getClient("echo2", EchoService.class); // <2>
1262
+ }
1263
+
1264
+ // ...
1265
+ }
1266
+ ----
1267
+ <1> Access the `EchoService` client proxy for group "echo1"
1268
+ <2> Access the `EchoService` client proxy for group "echo2"
0 commit comments