@@ -1130,3 +1130,139 @@ For more details and options such as suppressing error status codes, see the ref
11301130documentation for each client, as well as the Javadoc of `defaultStatusHandler` in
11311131`RestClient.Builder` or `WebClient.Builder`, and the `setErrorHandler` of `RestTemplate`.
11321132
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