Eagerly resolve Feign Client property values by default. Fix tests.
This commit is contained in:
@@ -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;
|
||||
*/
|
||||
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
|
||||
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<>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@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
|
||||
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
|
||||
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() {
|
||||
|
||||
@@ -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
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
* @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
|
||||
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
|
||||
.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
|
||||
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,
|
||||
|
||||
@@ -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;
|
||||
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
|
||||
|
||||
@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
|
||||
|
||||
@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
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
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;
|
||||
* @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 {
|
||||
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 {
|
||||
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 {
|
||||
@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 {
|
||||
|
||||
@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 {
|
||||
|
||||
}
|
||||
|
||||
@FeignClient("test")
|
||||
@FeignClient(value = "test", dismiss404 = true, url = "http://example.com")
|
||||
interface TestFeignClient {
|
||||
|
||||
@GetMapping
|
||||
void test();
|
||||
|
||||
}
|
||||
@@ -123,6 +147,7 @@ public class FeignChildContextInitializerTests {
|
||||
@FeignClient(value = "test-with-config", configuration = TestConfiguration.class)
|
||||
interface TestFeignClientWithConfig {
|
||||
|
||||
@GetMapping
|
||||
void test();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user