Browse Source

Eagerly resolve Feign Client property values by default. Fix tests.

aot-support
Olga Maciaszek-Sharma 2 years ago
parent
commit
77ca6f9535
  1. 32
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactory.java
  2. 24
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactoryBean.java
  3. 61
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsRegistrar.java
  4. 45
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/aot/FeignChildContextInitializer.java
  5. 63
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/aot/FeignClientBeanFactoryInitializationAotProcessor.java
  6. 43
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/aot/FeignAotTests.java

32
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactory.java

@ -16,11 +16,14 @@ @@ -16,11 +16,14 @@
package org.springframework.cloud.openfeign;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.cloud.context.named.NamedContextFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.lang.Nullable;
/**
@ -35,8 +38,15 @@ import org.springframework.lang.Nullable; @@ -35,8 +38,15 @@ import org.springframework.lang.Nullable;
*/
public class FeignClientFactory extends NamedContextFactory<FeignClientSpecification> {
private Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers;
public FeignClientFactory() {
this(new HashMap<>());
}
public FeignClientFactory(Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {
super(FeignClientsConfiguration.class, "spring.cloud.openfeign", "spring.cloud.openfeign.client.name");
this.applicationContextInitializers = applicationContextInitializers;
}
@Nullable
@ -58,4 +68,26 @@ public class FeignClientFactory extends NamedContextFactory<FeignClientSpecifica @@ -58,4 +68,26 @@ public class FeignClientFactory extends NamedContextFactory<FeignClientSpecifica
return getContext(contextName).getBean(beanName, type);
}
@SuppressWarnings("unchecked")
public FeignClientFactory withApplicationContextInitializers(
Map<String, Object> applicationContextInitializers) {
Map<String, ApplicationContextInitializer<GenericApplicationContext>> convertedInitializers = new HashMap<>();
applicationContextInitializers.keySet()
.forEach(contextId -> convertedInitializers.put(contextId,
(ApplicationContextInitializer<GenericApplicationContext>) applicationContextInitializers
.get(contextId)));
return new FeignClientFactory(convertedInitializers);
}
public void initializeChildContexts() {
applicationContextInitializers.keySet().forEach(contextId -> {
GenericApplicationContext childContext = buildContext(contextId);
applicationContextInitializers.get(contextId).initialize(childContext);
addContext(contextId, childContext);
childContext.refresh();
});
// Ensure the contexts are only initialized once after Aot processing
applicationContextInitializers = new HashMap<>();
}
}

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

@ -115,6 +115,13 @@ public class FeignClientFactoryBean @@ -115,6 +115,13 @@ public class FeignClientFactoryBean
private String[] qualifiers = new String[] {};
// For AOT testing
public FeignClientFactoryBean() {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating a FeignClientFactoryBean.");
}
}
@Override
public void afterPropertiesSet() {
Assert.hasText(contextId, "Context id must be set");
@ -411,9 +418,10 @@ public class FeignClientFactoryBean @@ -411,9 +418,10 @@ public class FeignClientFactoryBean
*/
@SuppressWarnings("unchecked")
<T> T getTarget() {
FeignClientFactory context = beanFactory != null ? beanFactory.getBean(FeignClientFactory.class)
: applicationContext.getBean(FeignClientFactory.class);
Feign.Builder builder = feign(context);
FeignClientFactory feignClientFactory = beanFactory != null ? beanFactory.getBean(FeignClientFactory.class)
: applicationContext.getBean(FeignClientFactory.class);
feignClientFactory.initializeChildContexts();
Feign.Builder builder = feign(feignClientFactory);
if (!StringUtils.hasText(url) && !isUrlAvailableInConfig(contextId)) {
if (LOG.isInfoEnabled()) {
@ -426,13 +434,13 @@ public class FeignClientFactoryBean @@ -426,13 +434,13 @@ public class FeignClientFactoryBean
url = name;
}
url += cleanPath();
return (T) loadBalance(builder, context, new HardCodedTarget<>(type, name, url));
return (T) loadBalance(builder, feignClientFactory, new HardCodedTarget<>(type, name, url));
}
if (StringUtils.hasText(url) && !url.startsWith("http")) {
url = "http://" + url;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
Client client = getOptional(feignClientFactory, Client.class);
if (client != null) {
if (client instanceof FeignBlockingLoadBalancerClient) {
// not load balancing because we have a url,
@ -447,10 +455,10 @@ public class FeignClientFactoryBean @@ -447,10 +455,10 @@ public class FeignClientFactoryBean
builder.client(client);
}
applyBuildCustomizers(context, builder);
applyBuildCustomizers(feignClientFactory, builder);
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, resolveTarget(context, contextId, url));
Targeter targeter = get(feignClientFactory, Targeter.class);
return targeter.target(this, builder, feignClientFactory, resolveTarget(feignClientFactory, contextId, url));
}
private String cleanPath() {

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

@ -205,11 +205,65 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo @@ -205,11 +205,65 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
@SuppressWarnings("unchecked")
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
Map<String, Object> attributes) {
Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
Class clazz = ClassUtils.resolveClassName(className, null);
// TODO: document change and correct AOT and contract usage
if (String.valueOf(false)
.equals(environment.getProperty("spring.cloud.openfeign.lazy-attributes-resolution", String.valueOf(false)))) {
eagerlyRegisterFeignClientBeanDefinition(className, attributes, registry);
}
else {
lazilyRegisterFeignClientBeanDefinition(className, attributes, registry);
}
}
private void eagerlyRegisterFeignClientBeanDefinition(String className, Map<String, Object> attributes, BeanDefinitionRegistry registry) {
// TODO: verify with prod method
validate(attributes);
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);
definition.addPropertyValue("url", getUrl(null, attributes));
definition.addPropertyValue("path", getPath(null, attributes));
String name = getName(attributes);
definition.addPropertyValue("name", name);
String contextId = getContextId(null, attributes);
definition.addPropertyValue("contextId", contextId);
definition.addPropertyValue("type", className);
definition.addPropertyValue("dismiss404", Boolean.parseBoolean(String.valueOf(attributes.get("dismiss404"))));
Object fallback = attributes.get("fallback");
if (fallback != null) {
definition.addPropertyValue("fallback", (fallback instanceof Class ? fallback
: ClassUtils.resolveClassName(fallback.toString(), null)));
}
Object fallbackFactory = attributes.get("fallbackFactory");
if (fallbackFactory != null) {
definition.addPropertyValue("fallbackFactory", fallbackFactory instanceof Class ? fallbackFactory
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
}
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
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
definition.addPropertyValue("qualifiers", qualifiers);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
// has a default, won't be null
boolean primary = (Boolean) attributes.get("primary");
beanDefinition.setPrimary(primary);
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
registerRefreshableBeanDefinition(registry, contextId, Request.Options.class, OptionsFactoryBean.class);
registerRefreshableBeanDefinition(registry, contextId, RefreshableUrl.class, RefreshableUrlFactoryBean.class);
}
private void lazilyRegisterFeignClientBeanDefinition(String className, Map<String, Object> attributes, BeanDefinitionRegistry registry) {
// TODO: verify with prod method
ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory
? (ConfigurableBeanFactory) registry : null;
Class clazz = ClassUtils.resolveClassName(className, null);
String contextId = getContextId(beanFactory, attributes);
String name = getName(attributes);
FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
@ -238,14 +292,13 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo @@ -238,14 +292,13 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
Object fallbackFactory = attributes.get("fallbackFactory");
if (fallbackFactory != null) {
factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
}
return factoryBean.getObject();
});
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
definition.setLazyInit(true);
validate(attributes);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean);

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

@ -16,12 +16,9 @@ import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; @@ -16,12 +16,9 @@ import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.cloud.openfeign.FeignClientFactory;
import org.springframework.cloud.openfeign.FeignClientSpecification;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.aot.ApplicationContextAotGenerator;
import org.springframework.context.support.GenericApplicationContext;
@ -35,22 +32,16 @@ import org.springframework.util.Assert; @@ -35,22 +32,16 @@ import org.springframework.util.Assert;
* @author Olga Maciaszek-Sharma
* @since 4.0.0
*/
public class FeignChildContextInitializer implements BeanRegistrationAotProcessor, ApplicationListener<WebServerInitializedEvent> {
public class FeignChildContextInitializer implements BeanRegistrationAotProcessor {
private final ApplicationContext applicationContext;
private final FeignClientFactory feignClientFactory;
private final Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers;
public FeignChildContextInitializer(ApplicationContext applicationContext, FeignClientFactory feignClientFactory) {
this(applicationContext, feignClientFactory, new HashMap<>());
}
public FeignChildContextInitializer(ApplicationContext applicationContext, FeignClientFactory feignClientFactory, Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {
this.applicationContext = applicationContext;
this.feignClientFactory = feignClientFactory;
this.applicationContextInitializers = applicationContextInitializers;
}
@Override
@ -58,7 +49,7 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso @@ -58,7 +49,7 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
ConfigurableApplicationContext context = ((ConfigurableApplicationContext) applicationContext);
BeanFactory applicationBeanFactory = context.getBeanFactory();
if (!(registeredBean.getBeanClass().equals(getClass())
if (!((registeredBean.getBeanClass().equals(FeignClientFactory.class))
&& registeredBean.getBeanFactory().equals(applicationBeanFactory))) {
return null;
}
@ -81,34 +72,6 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso @@ -81,34 +72,6 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
.collect(Collectors.toSet());
}
@SuppressWarnings("unchecked")
public FeignChildContextInitializer withApplicationContextInitializers(
Map<String, Object> applicationContextInitializers) {
Map<String, ApplicationContextInitializer<GenericApplicationContext>> convertedInitializers = new HashMap<>();
applicationContextInitializers.keySet()
.forEach(contextId -> convertedInitializers.put(contextId,
(ApplicationContextInitializer<GenericApplicationContext>) applicationContextInitializers
.get(contextId)));
return new FeignChildContextInitializer(applicationContext, feignClientFactory,
convertedInitializers);
}
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
if (applicationContext.equals(event.getApplicationContext())) {
applicationContextInitializers.keySet().forEach(contextId -> {
GenericApplicationContext childContext = feignClientFactory.buildContext(contextId);
applicationContextInitializers.get(contextId).initialize(childContext);
feignClientFactory.addContext(contextId, childContext);
childContext.refresh();
});
}
}
@Override
public boolean isBeanExcludedFromAotProcessing() {
return false;
}
private static class AotContribution implements BeanRegistrationAotContribution {
@ -140,8 +103,8 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso @@ -140,8 +103,8 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
method.addJavadoc("Use AOT child context management initialization")
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
.addParameter(RegisteredBean.class, "registeredBean")
.addParameter(FeignChildContextInitializer.class, "instance")
.returns(FeignChildContextInitializer.class)
.addParameter(FeignClientFactory.class, "instance")
.returns(FeignClientFactory.class)
.addStatement("$T<String, Object> initializers = new $T<>()", Map.class, HashMap.class);
generatedInitializerClassNames.keySet()
.forEach(contextId -> method.addStatement("initializers.put($S, new $L())", contextId,

63
spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/aot/FeignClientBeanFactoryInitializationAotProcessor.java

@ -9,6 +9,8 @@ import javax.lang.model.element.Modifier; @@ -9,6 +9,8 @@ import javax.lang.model.element.Modifier;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.MethodReference;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
@ -16,7 +18,6 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; @@ -16,7 +18,6 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
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.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@ -50,7 +51,8 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg @@ -50,7 +51,8 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg
@Override
public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) {
return feignClientBeanDefinitions
return registeredBean.getBeanClass()
.equals(FeignClientFactoryBean.class) || feignClientBeanDefinitions
.containsKey(registeredBean.getBeanClass().getName());
}
@ -66,10 +68,11 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg @@ -66,10 +68,11 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg
@Override
public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
if (!feignClientBeanDefinitions.isEmpty()) {
return new AotContribution(feignClientBeanDefinitions);
BeanFactory applicationBeanFactory = context.getBeanFactory();
if (feignClientBeanDefinitions.isEmpty() || !beanFactory.equals(applicationBeanFactory)) {
return null;
}
return null;
return new AotContribution(feignClientBeanDefinitions);
}
private static class AotContribution implements BeanFactoryInitializationAotContribution {
@ -88,13 +91,10 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg @@ -88,13 +91,10 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg
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");
MutablePropertyValues feignClientProperties = registeredBeanDefinition.getPropertyValues();
return beanFactoryInitializationCode.getMethods()
.add(buildMethodName(factoryBean.getType().getSimpleName()),
method -> generateFeignClientRegistrationMethod(method, factoryBean, registeredBeanDefinition))
.add(buildMethodName((String) feignClientProperties.get("type")),
method -> generateFeignClientRegistrationMethod(method, feignClientProperties, registeredBeanDefinition))
.getName();
}).collect(Collectors.toSet());
MethodReference initializerMethod = beanFactoryInitializationCode.getMethods()
@ -113,35 +113,32 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg @@ -113,35 +113,32 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg
feignClientRegistrationMethods.forEach(feignClientRegistrationMethod -> method.addStatement("$N(registry)", feignClientRegistrationMethod));
}
private void generateFeignClientRegistrationMethod(MethodSpec.Builder method, FeignClientFactoryBean registeredFactoryBean, GenericBeanDefinition registeredBeanDefinition) {
String qualifiers = "{\"" + String.join("\",\"", registeredFactoryBean.getQualifiers()) + "\"}";
private void generateFeignClientRegistrationMethod(MethodSpec.Builder method, MutablePropertyValues feignClientPropertyValues, GenericBeanDefinition registeredBeanDefinition) {
Object feignQualifiers = feignClientPropertyValues.get("qualifiers");
Assert.notNull(feignQualifiers, "Feign qualifiers cannot be null");
String qualifiers = "{\"" + String.join("\",\"", (String[]) feignQualifiers) + "\"}";
method
.addJavadoc("register Feign Client: $L", registeredBeanDefinition.getBeanClassName())
.addJavadoc("register Feign Client: $L", feignClientPropertyValues.get("type"))
.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("Class clazz = $T.resolveClassName(\"$L\", null)", ClassUtils.class, feignClientPropertyValues.get("type"))
.addStatement("$T definition = $T.genericBeanDefinition($T.class)", BeanDefinitionBuilder.class,
BeanDefinitionBuilder.class, FeignClientFactoryBean.class)
.addStatement("definition.addPropertyValue(\"name\",\"$L\")", feignClientPropertyValues.get("name"))
.addStatement("definition.addPropertyValue(\"contextId\", \"$L\")", feignClientPropertyValues.get("contextId"))
.addStatement("definition.addPropertyValue(\"type\", clazz)")
.addStatement("definition.addPropertyValue(\"url\", \"$L\")", feignClientPropertyValues.get("url"))
.addStatement("definition.addPropertyValue(\"path\", \"$L\")", feignClientPropertyValues.get("path"))
.addStatement("definition.addPropertyValue(\"dismiss404\", $L)", feignClientPropertyValues.get("dismiss404"))
.addStatement("definition.addPropertyValue(\"fallback\", $T.class)", feignClientPropertyValues.get("fallback"))
.addStatement("definition.addPropertyValue(\"fallbackFactory\", $T.class)", feignClientPropertyValues.get("fallbackFactory"))
.addStatement("definition.setAutowireMode($L)", registeredBeanDefinition.getAutowireMode())
.addStatement("definition.setLazyInit($L)", registeredBeanDefinition.getLazyInit())
.addStatement("definition.setLazyInit($L)", registeredBeanDefinition.getLazyInit() != null ? registeredBeanDefinition.getLazyInit() : false)
.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.setAttribute(\"$L\", clazz)", FactoryBean.OBJECT_TYPE_ATTRIBUTE)
.addStatement("beanDefinition.setPrimary($L)", registeredBeanDefinition.isPrimary())
.addStatement("$T holder = new $T(beanDefinition, \"$L\", new String[]$L)", BeanDefinitionHolder.class,
BeanDefinitionHolder.class, registeredBeanDefinition.getBeanClassName(), qualifiers)
BeanDefinitionHolder.class, feignClientPropertyValues.get("type"), qualifiers)
.addStatement("$T.registerBeanDefinition(holder, registry) ", BeanDefinitionReaderUtils.class);
}
}

43
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/aot/FeignChildContextInitializerTests.java → spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/aot/FeignAotTests.java

@ -10,13 +10,16 @@ import org.junit.jupiter.api.BeforeEach; @@ -10,13 +10,16 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.aot.AotDetector;
import org.springframework.aot.test.generate.TestGenerationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.context.annotation.UserConfigurations;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.cloud.openfeign.EnableFeignClients;
@ -31,6 +34,7 @@ import org.springframework.core.test.tools.CompileWithForkedClassLoader; @@ -31,6 +34,7 @@ import org.springframework.core.test.tools.CompileWithForkedClassLoader;
import org.springframework.core.test.tools.TestCompiler;
import org.springframework.javapoet.ClassName;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import static org.assertj.core.api.Assertions.assertThat;
@ -40,9 +44,9 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -40,9 +44,9 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Olga Maciaszek-Sharma
*/
@ExtendWith(OutputCaptureExtension.class)
public class FeignChildContextInitializerTests {
public class FeignAotTests {
private static final Log LOG = LogFactory.getLog(FeignChildContextInitializerTests.class);
private static final Log LOG = LogFactory.getLog(FeignAotTests.class);
@BeforeEach
@AfterEach
@ -59,7 +63,8 @@ public class FeignChildContextInitializerTests { @@ -59,7 +63,8 @@ public class FeignChildContextInitializerTests {
AnnotationConfigServletWebApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class,
FeignAutoConfiguration.class))
.withConfiguration(UserConfigurations.of(TestFeignConfiguration.class));
.withConfiguration(UserConfigurations.of(TestFeignConfiguration.class))
.withPropertyValues("logging.level.org.springframework.cloud=DEBUG");
contextRunner.prepare(context -> {
TestGenerationContext generationContext = new TestGenerationContext(TestTarget.class);
ClassName className = new ApplicationContextAotGenerator().processAheadOfTime(
@ -71,9 +76,17 @@ public class FeignChildContextInitializerTests { @@ -71,9 +76,17 @@ public class FeignChildContextInitializerTests {
ApplicationContextInitializer<GenericApplicationContext> initializer = compiled
.getInstance(ApplicationContextInitializer.class, className.toString());
initializer.initialize(freshApplicationContext);
assertThat(output).isNotEmpty();
// TODO
assertThat(output).contains("Creating a FeignClientFactoryBean.");
assertThat(output).contains("Refreshing FeignClientFactory-test-with-config",
"Refreshing FeignClientFactory-test");
assertThat(output).doesNotContain("Instantiating bean from Test custom config",
"Instantiating bean from default custom config");
TestPropertyValues.of(AotDetector.AOT_ENABLED + "=true")
.applyToSystemProperties(freshApplicationContext::refresh);
assertThat(output).contains("Instantiating bean from Test custom config",
"Instantiating bean from default custom config");
assertThat(freshApplicationContext.getBean(TestFeignClient.class)).isNotNull();
assertThat(freshApplicationContext.getBean(TestFeignClientWithConfig.class)).isNotNull();
});
});
}
@ -86,13 +99,21 @@ public class FeignChildContextInitializerTests { @@ -86,13 +99,21 @@ public class FeignChildContextInitializerTests {
@EnableFeignClients(clients = {TestFeignClient.class, TestFeignClientWithConfig.class}, defaultConfiguration = DefaultConfiguration.class)
public static class TestFeignConfiguration {
@Autowired
TestFeignClient testFeignClient;
@Autowired
TestFeignClientWithConfig testFeignClientWithConfig;
}
public static class TestConfiguration {
@Bean
TestBean testBean() {
LOG.debug("Instantiating bean from Test custom config");
if (LOG.isDebugEnabled()) {
LOG.debug("Instantiating bean from Test custom config");
}
return new TestBean();
}
@ -102,7 +123,9 @@ public class FeignChildContextInitializerTests { @@ -102,7 +123,9 @@ public class FeignChildContextInitializerTests {
@Bean
TestBean defaultTestBean() {
LOG.debug("Instantiating bean from default custom config");
if (LOG.isDebugEnabled()) {
LOG.debug("Instantiating bean from default custom config");
}
return new TestBean();
}
@ -112,9 +135,10 @@ public class FeignChildContextInitializerTests { @@ -112,9 +135,10 @@ public class FeignChildContextInitializerTests {
}
@FeignClient("test")
@FeignClient(value = "test", dismiss404 = true, url = "http://example.com")
interface TestFeignClient {
@GetMapping
void test();
}
@ -123,6 +147,7 @@ public class FeignChildContextInitializerTests { @@ -123,6 +147,7 @@ public class FeignChildContextInitializerTests {
@FeignClient(value = "test-with-config", configuration = TestConfiguration.class)
interface TestFeignClientWithConfig {
@GetMapping
void test();
}
Loading…
Cancel
Save