Polishing in HTTP service registry

This commit is contained in:
rstoyanchev
2025-05-01 11:00:20 +01:00
parent 42e854e5ff
commit 67f3ff574f
5 changed files with 67 additions and 61 deletions

View File

@@ -95,8 +95,8 @@ public final class HttpServiceProxyFactory {
@SuppressWarnings("unchecked")
private <S> S getProxy(Class<S> serviceType, List<HttpServiceMethod> httpServiceMethods) {
MethodInterceptor interceptor = new HttpServiceMethodInterceptor(httpServiceMethods);
ProxyFactory proxyFactory = new ProxyFactory(serviceType, interceptor);
return (S) proxyFactory.getProxy(serviceType.getClassLoader());
ProxyFactory factory = new ProxyFactory(serviceType, interceptor);
return (S) factory.getProxy(serviceType.getClassLoader());
}
private boolean isExchangeMethod(Method method) {

View File

@@ -144,7 +144,7 @@ public abstract class AbstractHttpServiceRegistrar implements
@Override
public final void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry beanRegistry) {
registerHttpServices(DefaultGroupSpec::new, metadata);
registerHttpServices(new DefaultGroupRegistry(), metadata);
RootBeanDefinition proxyRegistryBeanDef = createOrGetRegistry(beanRegistry);
@@ -264,45 +264,52 @@ public abstract class AbstractHttpServiceRegistrar implements
/**
* Default implementation of {@link GroupSpec}.
* Default implementation of {@link GroupRegistry}.
*/
private class DefaultGroupSpec implements GroupRegistry.GroupSpec {
private final GroupsMetadata.Registration registration;
DefaultGroupSpec(String groupName, HttpServiceGroup.ClientType clientType) {
clientType = (clientType != HttpServiceGroup.ClientType.UNSPECIFIED ? clientType : defaultClientType);
this.registration = groupsMetadata.getOrCreateGroup(groupName, clientType);
}
private class DefaultGroupRegistry implements GroupRegistry {
@Override
public GroupRegistry.GroupSpec register(Class<?>... serviceTypes) {
Arrays.stream(serviceTypes).map(Class::getName).forEach(this::register);
return this;
public GroupSpec forGroup(String name, HttpServiceGroup.ClientType clientType) {
return new DefaultGroupSpec(name, clientType);
}
@Override
public GroupRegistry.GroupSpec detectInBasePackages(Class<?>... packageClasses) {
Arrays.stream(packageClasses).map(Class::getPackageName).forEach(this::detectInBasePackage);
return this;
}
private class DefaultGroupSpec implements GroupSpec {
@Override
public GroupRegistry.GroupSpec detectInBasePackages(String... packageNames) {
Arrays.stream(packageNames).forEach(this::detectInBasePackage);
return this;
}
private final GroupsMetadata.Registration registration;
private void detectInBasePackage(String packageName) {
getScanner().findCandidateComponents(packageName)
.stream()
.map(BeanDefinition::getBeanClassName)
.filter(Objects::nonNull)
.forEach(this::register);
}
DefaultGroupSpec(String groupName, HttpServiceGroup.ClientType clientType) {
clientType = (clientType != HttpServiceGroup.ClientType.UNSPECIFIED ? clientType : defaultClientType);
this.registration = groupsMetadata.getOrCreateGroup(groupName, clientType);
}
private void register(String httpServiceTypeName) {
this.registration.httpServiceTypeNames().add(httpServiceTypeName);
@Override
public GroupRegistry.GroupSpec register(Class<?>... serviceTypes) {
Arrays.stream(serviceTypes).map(Class::getName).forEach(this::registerServiceTypeName);
return this;
}
@Override
public GroupRegistry.GroupSpec detectInBasePackages(Class<?>... packageClasses) {
Arrays.stream(packageClasses).map(Class::getPackageName).forEach(this::detectInBasePackage);
return this;
}
@Override
public GroupRegistry.GroupSpec detectInBasePackages(String... packageNames) {
Arrays.stream(packageNames).forEach(this::detectInBasePackage);
return this;
}
private void detectInBasePackage(String packageName) {
getScanner().findCandidateComponents(packageName).stream()
.map(BeanDefinition::getBeanClassName)
.filter(Objects::nonNull)
.forEach(this::registerServiceTypeName);
}
private void registerServiceTypeName(String httpServiceTypeName) {
this.registration.httpServiceTypeNames().add(httpServiceTypeName);
}
}
}

View File

@@ -34,7 +34,7 @@ import org.springframework.util.ClassUtils;
/**
* Container for HTTP Service type registrations, initially storing HTTP Service
* type names as {@link Registration}s, and later exposing access to those
* registrations as {@link HttpServiceGroup}s via {@link #groups()}.
* registrations as {@link HttpServiceGroup}s via {@link #groups(ClassLoader)}.
*
* @author Rossen Stoyanchev
* @since 7.0
@@ -85,14 +85,13 @@ final class GroupsMetadata {
* Create the {@link HttpServiceGroup}s for all registrations.
*/
public Collection<HttpServiceGroup> groups(@Nullable ClassLoader classLoader) {
return this.groupMap.values()
.stream()
return this.groupMap.values().stream()
.map(registration -> registration.toHttpServiceGroup(classLoader))
.toList();
}
/**
* Return the raw {@link DefaultRegistration registrations}.
* Return the raw {@link Registration registrations}.
*/
Stream<Registration> registrations() {
return this.groupMap.values().stream();
@@ -146,11 +145,15 @@ final class GroupsMetadata {
* Create the {@link HttpServiceGroup} from the metadata.
*/
public HttpServiceGroup toHttpServiceGroup(@Nullable ClassLoader classLoader) {
return new RegisteredGroup(this.name,
(this.clientType.isUnspecified() ? HttpServiceGroup.ClientType.REST_CLIENT : this.clientType),
this.httpServiceTypeNames.stream()
.map(typeName -> ClassUtils.resolveClassName(typeName, classLoader))
.collect(Collectors.toSet()));
HttpServiceGroup.ClientType clientTypeToUse =
(this.clientType.isUnspecified() ? HttpServiceGroup.ClientType.REST_CLIENT : this.clientType);
Set<Class<?>> httpServiceTypes = this.httpServiceTypeNames.stream()
.map(typeName -> ClassUtils.resolveClassName(typeName, classLoader))
.collect(Collectors.toSet());
return new RegisteredGroup(this.name, clientTypeToUse, httpServiceTypes);
}
@Override

View File

@@ -101,10 +101,9 @@ public final class HttpServiceProxyRegistryFactoryBean
Assert.notNull(this.beanClassLoader, "BeanClassLoader not initialized");
// Create the groups from the metadata
Set<ProxyHttpServiceGroup> groups = this.groupsMetadata.groups(this.beanClassLoader)
.stream()
.map(ProxyHttpServiceGroup::new)
.collect(Collectors.toSet());
Set<ProxyHttpServiceGroup> groups = this.groupsMetadata.groups(this.beanClassLoader).stream()
.map(ProxyHttpServiceGroup::new)
.collect(Collectors.toSet());
// Apply group configurers
groupAdapters.forEach((clientType, groupAdapter) ->
@@ -170,15 +169,16 @@ public final class HttpServiceProxyRegistryFactoryBean
private BiConsumer<HttpServiceGroup, HttpServiceProxyFactory.Builder> proxyFactoryConfigurer = (group, builder) -> {};
ProxyHttpServiceGroup(HttpServiceGroup group) {
this(group, getHttpServiceGroupAdapter(group.clientType()));
}
ProxyHttpServiceGroup(HttpServiceGroup group, HttpServiceGroupAdapter<?> groupAdapter) {
this.declaredGroup = group;
this.groupAdapter = groupAdapter;
this.clientBuilder = groupAdapter.createClientBuilder();
this.groupAdapter = getGroupAdapter(group.clientType());
this.clientBuilder = this.groupAdapter.createClientBuilder();
}
private static HttpServiceGroupAdapter<?> getGroupAdapter(HttpServiceGroup.ClientType clientType) {
HttpServiceGroupAdapter<?> adapter = groupAdapters.get(clientType);
Assert.state(adapter != null, "No HttpServiceGroupAdapter for type " + clientType);
return adapter;
}
@Override
public String name() {
@@ -224,11 +224,6 @@ public final class HttpServiceProxyRegistryFactoryBean
return getClass().getSimpleName() + "[id=" + name() + "]";
}
private static HttpServiceGroupAdapter<?> getHttpServiceGroupAdapter(HttpServiceGroup.ClientType clientType) {
HttpServiceGroupAdapter<?> adapter = groupAdapters.get(clientType);
Assert.state(adapter != null, "No HttpServiceGroupAdapter for type " + clientType);
return adapter;
}
}

View File

@@ -123,13 +123,14 @@ public class RestClientProxyRegistryIntegrationTests {
return className.contains("EchoA");
};
};
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setClassLoader(beanClassLoader);
context.register(ClassUtils.resolveClassName(ListingConfig.class.getName(), beanClassLoader));
context.refresh();
assertThat(context.getBean(ClassUtils.resolveClassName(EchoA.class.getName(), beanClassLoader))
.getClass()
.getClassLoader()).isSameAs(beanClassLoader);
Class<?> echoClass = ClassUtils.resolveClassName(EchoA.class.getName(), beanClassLoader);
assertThat(context.getBean(echoClass).getClass().getClassLoader()).isSameAs(beanClassLoader);
}
private static class ClientConfig {