Browse Source

Create AOT contribution for FeignClient beans.

aot-support
Olga Maciaszek-Sharma 2 years ago
parent
commit
577153a40c
  1. 3
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java
  2. 10
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactoryBean.java
  3. 37
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientSpecification.java
  4. 22
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsRegistrar.java
  5. 123
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/aot/FeignChildContextInitializer.java
  6. 12
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientFactoryTest.java
  7. 8
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientFactoryTests.java
  8. 2
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/aot/FeignChildContextInitializerTests.java

3
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java

@ -66,6 +66,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager;
@ -111,7 +112,7 @@ public class FeignAutoConfiguration {
} }
@Bean @Bean
static FeignChildContextInitializer feignChildContextInitializer(ApplicationContext parentContext, static FeignChildContextInitializer feignChildContextInitializer(GenericApplicationContext parentContext,
FeignClientFactory feignClientFactory) { FeignClientFactory feignClientFactory) {
return new FeignChildContextInitializer(parentContext, feignClientFactory); return new FeignChildContextInitializer(parentContext, feignClientFactory);
} }

10
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactoryBean.java

@ -113,6 +113,8 @@ public class FeignClientFactoryBean
private final List<FeignBuilderCustomizer> additionalCustomizers = new ArrayList<>(); private final List<FeignBuilderCustomizer> additionalCustomizers = new ArrayList<>();
private String[] qualifiers = new String[] {};
@Override @Override
public void afterPropertiesSet() { public void afterPropertiesSet() {
Assert.hasText(contextId, "Context id must be set"); Assert.hasText(contextId, "Context id must be set");
@ -600,6 +602,14 @@ public class FeignClientFactoryBean
this.refreshableClient = refreshableClient; this.refreshableClient = refreshableClient;
} }
public String[] getQualifiers() {
return qualifiers;
}
public void setQualifiers(String[] qualifiers) {
this.qualifiers = qualifiers;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {

37
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientSpecification.java

@ -29,13 +29,16 @@ public class FeignClientSpecification implements NamedContextFactory.Specificati
private String name; private String name;
private String className;
private Class<?>[] configuration; private Class<?>[] configuration;
FeignClientSpecification() { public FeignClientSpecification() {
} }
public FeignClientSpecification(String name, Class<?>[] configuration) { public FeignClientSpecification(String name, String className, Class<?>[] configuration) {
this.name = name; this.name = name;
this.className = className;
this.configuration = configuration; this.configuration = configuration;
} }
@ -47,6 +50,14 @@ public class FeignClientSpecification implements NamedContextFactory.Specificati
this.name = name; this.name = name;
} }
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public Class<?>[] getConfiguration() { public Class<?>[] getConfiguration() {
return this.configuration; return this.configuration;
} }
@ -57,25 +68,25 @@ public class FeignClientSpecification implements NamedContextFactory.Specificati
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) return true;
return true; if (!(o instanceof FeignClientSpecification that)) return false;
} return Objects.equals(name, that.name) && Objects.equals(className, that.className) && Arrays.equals(configuration, that.configuration);
if (o == null || getClass() != o.getClass()) {
return false;
}
FeignClientSpecification that = (FeignClientSpecification) o;
return Objects.equals(name, that.name) && Arrays.equals(configuration, that.configuration);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(name, Arrays.hashCode(configuration)); int result = Objects.hash(name, className);
result = 31 * result + Arrays.hashCode(configuration);
return result;
} }
@Override @Override
public String toString() { public String toString() {
return new StringBuilder("FeignClientSpecification{").append("name='").append(name).append("', ") return "FeignClientSpecification{" + "name='"
.append("configuration=").append(Arrays.toString(configuration)).append("}").toString(); + name + "', "
+ "className='" + className + "', "
+ "configuration=" + Arrays.toString(configuration) + "}";
} }
} }

22
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsRegistrar.java

@ -162,12 +162,11 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
else { else {
name = "default." + metadata.getClassName(); name = "default." + metadata.getClassName();
} }
registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); registerClientConfiguration(registry, name, "default", defaultAttrs.get("defaultConfiguration"));
} }
} }
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>(); LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName()); Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
@ -196,7 +195,8 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
.getAnnotationAttributes(FeignClient.class.getCanonicalName()); .getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = getClientName(attributes); String name = getClientName(attributes);
registerClientConfiguration(registry, name, attributes.get("configuration")); String className = annotationMetadata.getClassName();
registerClientConfiguration(registry, name, className, attributes.get("configuration"));
registerFeignClient(registry, annotationMetadata, attributes); registerFeignClient(registry, annotationMetadata, attributes);
} }
@ -218,6 +218,14 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
factoryBean.setContextId(contextId); factoryBean.setContextId(contextId);
factoryBean.setType(clazz); factoryBean.setType(clazz);
factoryBean.setRefreshableClient(isClientRefreshEnabled()); factoryBean.setRefreshableClient(isClientRefreshEnabled());
String[] qualifiers = getQualifiers(attributes);
if (ObjectUtils.isEmpty(qualifiers)) {
qualifiers = new String[] {contextId + "FeignClient"};
}
// This is done so that there's a way to retrieve qualifiers while generating AOT code
factoryBean.setQualifiers(qualifiers);
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> { BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
factoryBean.setUrl(getUrl(beanFactory, attributes)); factoryBean.setUrl(getUrl(beanFactory, attributes));
factoryBean.setPath(getPath(beanFactory, attributes)); factoryBean.setPath(getPath(beanFactory, attributes));
@ -247,11 +255,6 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
beanDefinition.setPrimary(primary); beanDefinition.setPrimary(primary);
String[] qualifiers = getQualifiers(attributes);
if (ObjectUtils.isEmpty(qualifiers)) {
qualifiers = new String[] { contextId + "FeignClient" };
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers); BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
@ -407,9 +410,10 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
"Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName()); "Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());
} }
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object className, Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class); BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name); builder.addConstructorArgValue(name);
builder.addConstructorArgValue(className);
builder.addConstructorArgValue(configuration); builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition()); builder.getBeanDefinition());

123
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/aot/FeignChildContextInitializer.java

@ -4,6 +4,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -12,21 +13,33 @@ import javax.lang.model.element.Modifier;
import org.springframework.aot.generate.GeneratedMethod; import org.springframework.aot.generate.GeneratedMethod;
import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.generate.GenerationContext;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode; import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.cloud.openfeign.FeignClientFactory; import org.springframework.cloud.openfeign.FeignClientFactory;
import org.springframework.cloud.openfeign.FeignClientFactoryBean;
import org.springframework.cloud.openfeign.FeignClientSpecification; import org.springframework.cloud.openfeign.FeignClientSpecification;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.aot.ApplicationContextAotGenerator; import org.springframework.context.aot.ApplicationContextAotGenerator;
import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericApplicationContext;
import org.springframework.javapoet.ClassName; import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.MethodSpec;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/** /**
* A {@link BeanRegistrationAotProcessor} that creates an {@link BeanRegistrationAotContribution} for * A {@link BeanRegistrationAotProcessor} that creates an {@link BeanRegistrationAotContribution} for
@ -35,28 +48,32 @@ import org.springframework.util.Assert;
* @author Olga Maciaszek-Sharma * @author Olga Maciaszek-Sharma
* @since 4.0.0 * @since 4.0.0
*/ */
public class FeignChildContextInitializer implements BeanRegistrationAotProcessor, ApplicationListener<WebServerInitializedEvent> { public class FeignChildContextInitializer implements BeanRegistrationAotProcessor, ApplicationListener<WebServerInitializedEvent>,
BeanRegistrationExcludeFilter {
private final ApplicationContext applicationContext; private final GenericApplicationContext context;
private final FeignClientFactory feignClientFactory; private final FeignClientFactory feignClientFactory;
private final Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers; private final Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers;
public FeignChildContextInitializer(ApplicationContext applicationContext, FeignClientFactory feignClientFactory) { private final Map<String, BeanDefinition> feignClientBeanDefinitions;
this(applicationContext, feignClientFactory, new HashMap<>());
public FeignChildContextInitializer(GenericApplicationContext context, FeignClientFactory feignClientFactory) {
this(context, feignClientFactory, new HashMap<>());
} }
public FeignChildContextInitializer(ApplicationContext applicationContext, FeignClientFactory feignClientFactory, Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) { public FeignChildContextInitializer(GenericApplicationContext context, FeignClientFactory feignClientFactory, Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {
this.applicationContext = applicationContext; this.context = context;
this.feignClientFactory = feignClientFactory; this.feignClientFactory = feignClientFactory;
this.applicationContextInitializers = applicationContextInitializers; this.applicationContextInitializers = applicationContextInitializers;
feignClientBeanDefinitions = getFeignClientClassNames();
} }
@Override @Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext); Assert.isInstanceOf(ConfigurableApplicationContext.class, context);
ConfigurableApplicationContext context = ((ConfigurableApplicationContext) applicationContext); ConfigurableApplicationContext context = this.context;
BeanFactory applicationBeanFactory = context.getBeanFactory(); BeanFactory applicationBeanFactory = context.getBeanFactory();
if (!(registeredBean.getBeanClass().equals(getClass()) if (!(registeredBean.getBeanClass().equals(getClass())
&& registeredBean.getBeanFactory().equals(applicationBeanFactory))) { && registeredBean.getBeanFactory().equals(applicationBeanFactory))) {
@ -66,7 +83,7 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
Map<String, GenericApplicationContext> childContextAotContributions = contextIds.stream() Map<String, GenericApplicationContext> childContextAotContributions = contextIds.stream()
.map(contextId -> Map.entry(contextId, buildChildContext(contextId))) .map(contextId -> Map.entry(contextId, buildChildContext(contextId)))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return new AotContribution(childContextAotContributions); return new AotContribution(childContextAotContributions, feignClientBeanDefinitions);
} }
private GenericApplicationContext buildChildContext(String contextId) { private GenericApplicationContext buildChildContext(String contextId) {
@ -89,13 +106,13 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
.forEach(contextId -> convertedInitializers.put(contextId, .forEach(contextId -> convertedInitializers.put(contextId,
(ApplicationContextInitializer<GenericApplicationContext>) applicationContextInitializers (ApplicationContextInitializer<GenericApplicationContext>) applicationContextInitializers
.get(contextId))); .get(contextId)));
return new FeignChildContextInitializer(applicationContext, feignClientFactory, return new FeignChildContextInitializer(context, feignClientFactory,
convertedInitializers); convertedInitializers);
} }
@Override @Override
public void onApplicationEvent(WebServerInitializedEvent event) { public void onApplicationEvent(WebServerInitializedEvent event) {
if (applicationContext.equals(event.getApplicationContext())) { if (context.equals(event.getApplicationContext())) {
applicationContextInitializers.keySet().forEach(contextId -> { applicationContextInitializers.keySet().forEach(contextId -> {
GenericApplicationContext childContext = feignClientFactory.buildContext(contextId); GenericApplicationContext childContext = feignClientFactory.buildContext(contextId);
applicationContextInitializers.get(contextId).initialize(childContext); applicationContextInitializers.get(contextId).initialize(childContext);
@ -110,15 +127,33 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
return false; return false;
} }
@Override
public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) {
return feignClientBeanDefinitions
.containsKey(registeredBean.getBeanClass().getName());
}
private Map<String, BeanDefinition> getFeignClientClassNames() {
Map<String, FeignClientSpecification> configurations = feignClientFactory.getConfigurations();
return configurations.values().stream()
.map(FeignClientSpecification::getClassName)
.filter(Objects::nonNull)
.filter(className -> !className.equals("default"))
.map(className -> Map.entry(className, context.getBeanDefinition(className)))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
private static class AotContribution implements BeanRegistrationAotContribution { private static class AotContribution implements BeanRegistrationAotContribution {
private final Map<String, GenericApplicationContext> childContexts; private final Map<String, GenericApplicationContext> childContexts;
private final Map<String, BeanDefinition> feignClientBeanDefinitions;
public AotContribution(Map<String, GenericApplicationContext> childContexts) { public AotContribution(Map<String, GenericApplicationContext> childContexts, Map<String, BeanDefinition> feignClientBeanDefinitions) {
this.childContexts = childContexts.entrySet().stream() this.childContexts = childContexts.entrySet().stream()
.filter(entry -> entry.getValue() != null) .filter(entry -> entry.getValue() != null)
.map(entry -> Map.entry(entry.getKey(), entry.getValue())) .map(entry -> Map.entry(entry.getKey(), entry.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
this.feignClientBeanDefinitions = feignClientBeanDefinitions;
} }
@Override @Override
@ -149,6 +184,68 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
method.addStatement("return instance.withApplicationContextInitializers(initializers)"); method.addStatement("return instance.withApplicationContextInitializers(initializers)");
}); });
beanRegistrationCode.addInstancePostProcessor(postProcessorMethod.toMethodReference()); beanRegistrationCode.addInstancePostProcessor(postProcessorMethod.toMethodReference());
// TODO: ensure the methods are called
feignClientBeanDefinitions.values().forEach(beanDefinition -> {
// TODO: handle problem retrieving
Assert.notNull(beanDefinition, "beanDefinition cannot be null");
Assert.isInstanceOf(GenericBeanDefinition.class, beanDefinition);
GenericBeanDefinition registeredBeanDefinition = (GenericBeanDefinition) beanDefinition;
Object factoryBeanObject = registeredBeanDefinition.getAttribute("feignClientsRegistrarFactoryBean");
Assert.isInstanceOf(FeignClientFactoryBean.class, factoryBeanObject);
FeignClientFactoryBean factoryBean = (FeignClientFactoryBean) factoryBeanObject;
Assert.notNull(factoryBean, "factoryBean cannot be null");
generationContext.getGeneratedClasses()
// FIXME: correct generation context
.getOrAddForFeatureComponent(registeredBeanDefinition.getBeanClassName(), generatedInitializerClassNames.get(factoryBean.getContextId()), type -> {
type.addMethod(buildMethodSpec(factoryBean, registeredBeanDefinition));
}
);
});
}
// TODO: verify all factory bean method values from registrar!
private MethodSpec buildMethodSpec(FeignClientFactoryBean registeredFactoryBean, GenericBeanDefinition registeredBeanDefinition) {
String qualifiers = "{\"" + String.join("\",\"", registeredFactoryBean.getQualifiers()) + "\"}";
return MethodSpec.methodBuilder("feignClientRegistration")
.addJavadoc("registerFeignClient")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(BeanDefinitionRegistry.class, "registry")
.addStatement("Class clazz = $T.resolveClassName(\"$L\", null)", ClassUtils.class, registeredBeanDefinition.getBeanClassName())
.addStatement("$T beanFactory = registry instanceof $T ? ($T) registry : null",
ConfigurableBeanFactory.class, ConfigurableBeanFactory.class, ConfigurableBeanFactory.class)
.addStatement("$T factoryBean = new $T()", FeignClientFactoryBean.class, FeignClientFactoryBean.class)
.addStatement("factoryBean.setBeanFactory(beanFactory)")
.addStatement("factoryBean.setName(\"$L\")", registeredFactoryBean.getName())
.addStatement("factoryBean.setContextId(\"$L\")", registeredFactoryBean.getContextId())
.addStatement("factoryBean.setType($T.class)", registeredFactoryBean.getType())
.addStatement("factoryBean.setUrl($L)", registeredFactoryBean.getUrl())
.addStatement("factoryBean.setPath($L)", registeredFactoryBean.getPath())
.addStatement("factoryBean.setDismiss404($L)", registeredFactoryBean.isDismiss404())
.addStatement("factoryBean.setFallback($T.class)", registeredFactoryBean.getFallback())
.addStatement("factoryBean.setFallbackFactory($T.class)", registeredFactoryBean.getFallbackFactory())
.addStatement("$T definition = $T.genericBeanDefinition(clazz, () -> factoryBean.getObject())", BeanDefinitionBuilder.class,
BeanDefinitionBuilder.class)
.addStatement("definition.setAutowireMode($L)", registeredBeanDefinition.getAutowireMode())
.addStatement("definition.setLazyInit($L)", registeredBeanDefinition.getLazyInit())
.addStatement("$T beanDefinition = definition.getBeanDefinition()", AbstractBeanDefinition.class)
.addStatement("beanDefinition.setAttribute(\"$L\", $T.class)", FactoryBean.OBJECT_TYPE_ATTRIBUTE, registeredFactoryBean.getType())
.addStatement("beanDefinition.setAttribute(\"feignClientsRegistrarFactoryBean\", factoryBean)")
.addStatement("beanDefinition.setPrimary($L)", registeredBeanDefinition.isPrimary())
.addStatement("String[] qualifiers = new String[]{}")
.addStatement("$T holder = new $T(beanDefinition, \"$L\", new String[]$L)", BeanDefinitionHolder.class,
BeanDefinitionHolder.class, registeredBeanDefinition.getBeanClassName(), qualifiers)
.addStatement("$T.registerBeanDefinition(holder, registry) ", BeanDefinitionReaderUtils.class)
.build();
// TODO
// .addStatement("Class<?> beanType = $T.class", Class.forName(feignClientBeanDefinition.getBeanClassName()))
// .addStatement("$T beanDefinition = new $T(beanType)", RootBeanDefinition.class, RootBeanDefinition.class)
// .addStatement("beanDefinition.setLazyInit($L)", feignClientBeanDefinition.isLazyInit())
// .addStatement("beanDefinition.setInstanceSupplier(($T<Object>) registeredBean -> new $T())", InstanceSupplier.class, FeignClientFactoryBean.class)
// .addStatement("return beanDefinition")
} }
} }

12
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientFactoryTest.java

@ -39,15 +39,15 @@ class FeignClientFactoryTest {
FeignClientFactory feignClientFactory = new FeignClientFactory(); FeignClientFactory feignClientFactory = new FeignClientFactory();
feignClientFactory.setApplicationContext(parent); feignClientFactory.setApplicationContext(parent);
feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("empty", EmptyConfiguration.class))); feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("empty", null, EmptyConfiguration.class)));
Logger.Level level = feignClientFactory.getInstanceWithoutAncestors("empty", Logger.Level.class); Logger.Level level = feignClientFactory.getInstanceWithoutAncestors("empty", Logger.Level.class);
assertThat(level).as("Logger was not null").isNull(); assertThat(level).as("Logger was not null").isNull();
} }
private FeignClientSpecification getSpec(String name, Class<?> configClass) { private FeignClientSpecification getSpec(String name, String className, Class<?> configClass) {
return new FeignClientSpecification(name, new Class[] { configClass }); return new FeignClientSpecification(name, className, new Class[] {configClass});
} }
@Test @Test
@ -57,7 +57,7 @@ class FeignClientFactoryTest {
FeignClientFactory feignClientFactory = new FeignClientFactory(); FeignClientFactory feignClientFactory = new FeignClientFactory();
feignClientFactory.setApplicationContext(parent); feignClientFactory.setApplicationContext(parent);
feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("empty", EmptyConfiguration.class))); feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("empty", null, EmptyConfiguration.class)));
Collection<RequestInterceptor> interceptors = feignClientFactory Collection<RequestInterceptor> interceptors = feignClientFactory
.getInstancesWithoutAncestors("empty", RequestInterceptor.class).values(); .getInstancesWithoutAncestors("empty", RequestInterceptor.class).values();
@ -72,7 +72,7 @@ class FeignClientFactoryTest {
FeignClientFactory feignClientFactory = new FeignClientFactory(); FeignClientFactory feignClientFactory = new FeignClientFactory();
feignClientFactory.setApplicationContext(parent); feignClientFactory.setApplicationContext(parent);
feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("demo", DemoConfiguration.class))); feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("demo", null, DemoConfiguration.class)));
Logger.Level level = feignClientFactory.getInstanceWithoutAncestors("demo", Logger.Level.class); Logger.Level level = feignClientFactory.getInstanceWithoutAncestors("demo", Logger.Level.class);
@ -86,7 +86,7 @@ class FeignClientFactoryTest {
FeignClientFactory feignClientFactory = new FeignClientFactory(); FeignClientFactory feignClientFactory = new FeignClientFactory();
feignClientFactory.setApplicationContext(parent); feignClientFactory.setApplicationContext(parent);
feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("demo", DemoConfiguration.class))); feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("demo", null, DemoConfiguration.class)));
Collection<RequestInterceptor> interceptors = feignClientFactory Collection<RequestInterceptor> interceptors = feignClientFactory
.getInstancesWithoutAncestors("demo", RequestInterceptor.class).values(); .getInstancesWithoutAncestors("demo", RequestInterceptor.class).values();

8
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientFactoryTests.java

@ -54,7 +54,7 @@ public class FeignClientFactoryTests {
parent.refresh(); parent.refresh();
FeignClientFactory context = new FeignClientFactory(); FeignClientFactory context = new FeignClientFactory();
context.setApplicationContext(parent); context.setApplicationContext(parent);
context.setConfigurations(Arrays.asList(getSpec("foo", FooConfig.class), getSpec("bar", BarConfig.class))); context.setConfigurations(Arrays.asList(getSpec("foo", null, FooConfig.class), getSpec("bar", null, BarConfig.class)));
Foo foo = context.getInstance("foo", Foo.class); Foo foo = context.getInstance("foo", Foo.class);
assertThat(foo).as("foo was null").isNotNull(); assertThat(foo).as("foo was null").isNotNull();
@ -83,8 +83,8 @@ public class FeignClientFactoryTests {
assertThat(client).isInstanceOf(Client.Default.class); assertThat(client).isInstanceOf(Client.Default.class);
} }
private FeignClientSpecification getSpec(String name, Class<?> configClass) { private FeignClientSpecification getSpec(String name, String className, Class<?> configClass) {
return new FeignClientSpecification(name, new Class[] { configClass }); return new FeignClientSpecification(name, className, new Class[] {configClass});
} }
interface TestType { interface TestType {
@ -106,7 +106,7 @@ public class FeignClientFactoryTests {
FeignClientFactory feignContext() { FeignClientFactory feignContext() {
FeignClientFactory feignClientFactory = new FeignClientFactory(); FeignClientFactory feignClientFactory = new FeignClientFactory();
feignClientFactory.setConfigurations(Collections.singletonList( feignClientFactory.setConfigurations(Collections.singletonList(
new FeignClientSpecification("test", new Class[] { LoadBalancerAutoConfiguration.class }))); new FeignClientSpecification("test", null, new Class[] {LoadBalancerAutoConfiguration.class})));
return feignClientFactory; return feignClientFactory;
} }

2
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/aot/FeignChildContextInitializerTests.java

@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Olga Maciaszek-Sharma * @author Olga Maciaszek-Sharma
*/ */
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
class FeignChildContextInitializerTests { public class FeignChildContextInitializerTests {
private static final Log LOG = LogFactory.getLog(FeignChildContextInitializerTests.class); private static final Log LOG = LogFactory.getLog(FeignChildContextInitializerTests.class);

Loading…
Cancel
Save