Fix checkstyle. Reformat.
This commit is contained in:
@@ -113,13 +113,13 @@ public class FeignAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
static FeignChildContextInitializer feignChildContextInitializer(GenericApplicationContext parentContext,
|
||||
FeignClientFactory feignClientFactory) {
|
||||
FeignClientFactory feignClientFactory) {
|
||||
return new FeignChildContextInitializer(parentContext, feignClientFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
static FeignClientBeanFactoryInitializationAotProcessor feignClientBeanFactoryInitializationCodeGenerator(GenericApplicationContext applicationContext,
|
||||
FeignClientFactory feignClientFactory) {
|
||||
static FeignClientBeanFactoryInitializationAotProcessor feignClientBeanFactoryInitializationCodeGenerator(
|
||||
GenericApplicationContext applicationContext, FeignClientFactory feignClientFactory) {
|
||||
return new FeignClientBeanFactoryInitializationAotProcessor(applicationContext, feignClientFactory);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ public class FeignAutoConfiguration {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({Module.class, Page.class, Sort.class})
|
||||
@ConditionalOnClass({ Module.class, Page.class, Sort.class })
|
||||
@ConditionalOnProperty(value = "spring.cloud.openfeign.autoconfiguration.jackson.enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
protected static class FeignJacksonConfiguration {
|
||||
|
||||
@@ -44,7 +44,8 @@ public class FeignClientFactory extends NamedContextFactory<FeignClientSpecifica
|
||||
this(new HashMap<>());
|
||||
}
|
||||
|
||||
public FeignClientFactory(Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {
|
||||
public FeignClientFactory(
|
||||
Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {
|
||||
super(FeignClientsConfiguration.class, "spring.cloud.openfeign", "spring.cloud.openfeign.client.name");
|
||||
this.applicationContextInitializers = applicationContextInitializers;
|
||||
}
|
||||
@@ -69,13 +70,12 @@ public class FeignClientFactory extends NamedContextFactory<FeignClientSpecifica
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public FeignClientFactory withApplicationContextInitializers(
|
||||
Map<String, Object> applicationContextInitializers) {
|
||||
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)));
|
||||
.forEach(contextId -> convertedInitializers.put(contextId,
|
||||
(ApplicationContextInitializer<GenericApplicationContext>) applicationContextInitializers
|
||||
.get(contextId)));
|
||||
return new FeignClientFactory(convertedInitializers);
|
||||
}
|
||||
|
||||
@@ -89,5 +89,5 @@ public class FeignClientFactory extends NamedContextFactory<FeignClientSpecifica
|
||||
// Ensure the contexts are only initialized once after Aot processing
|
||||
applicationContextInitializers = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ public class FeignClientFactoryBean
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> T getTarget() {
|
||||
FeignClientFactory feignClientFactory = beanFactory != null ? beanFactory.getBean(FeignClientFactory.class)
|
||||
: applicationContext.getBean(FeignClientFactory.class);
|
||||
: applicationContext.getBean(FeignClientFactory.class);
|
||||
feignClientFactory.initializeChildContexts();
|
||||
Feign.Builder builder = feign(feignClientFactory);
|
||||
if (!StringUtils.hasText(url) && !isUrlAvailableInConfig(contextId)) {
|
||||
|
||||
@@ -68,9 +68,14 @@ public class FeignClientSpecification implements NamedContextFactory.Specificati
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) 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 (this == o) {
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,13 +85,10 @@ public class FeignClientSpecification implements NamedContextFactory.Specificati
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FeignClientSpecification{" + "name='"
|
||||
+ name + "', "
|
||||
+ "className='" + className + "', "
|
||||
+ "configuration=" + Arrays.toString(configuration) + "}";
|
||||
return "FeignClientSpecification{" + "name='" + name + "', " + "className='" + className + "', "
|
||||
+ "configuration=" + Arrays.toString(configuration) + "}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
|
||||
Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
|
||||
|
||||
Map<String, Object> attributes = annotationMetadata
|
||||
.getAnnotationAttributes(FeignClient.class.getCanonicalName());
|
||||
.getAnnotationAttributes(FeignClient.class.getCanonicalName());
|
||||
|
||||
String name = getClientName(attributes);
|
||||
String className = annotationMetadata.getClassName();
|
||||
@@ -203,13 +203,12 @@ 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();
|
||||
// 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)))) {
|
||||
if (String.valueOf(false).equals(
|
||||
environment.getProperty("spring.cloud.openfeign.lazy-attributes-resolution", String.valueOf(false)))) {
|
||||
eagerlyRegisterFeignClientBeanDefinition(className, attributes, registry);
|
||||
}
|
||||
else {
|
||||
@@ -217,11 +216,10 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
|
||||
}
|
||||
}
|
||||
|
||||
private void eagerlyRegisterFeignClientBeanDefinition(String className, Map<String, Object> attributes, BeanDefinitionRegistry registry) {
|
||||
// TODO: verify with prod method
|
||||
private void eagerlyRegisterFeignClientBeanDefinition(String className, Map<String, Object> attributes,
|
||||
BeanDefinitionRegistry registry) {
|
||||
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);
|
||||
@@ -232,21 +230,22 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
|
||||
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)));
|
||||
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));
|
||||
: 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"};
|
||||
qualifiers = new String[] { contextId + "FeignClient" };
|
||||
}
|
||||
// This is done so that there's a way to retrieve qualifiers while generating AOT code
|
||||
// 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);
|
||||
@@ -259,10 +258,10 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
|
||||
registerRefreshableBeanDefinition(registry, contextId, RefreshableUrl.class, RefreshableUrlFactoryBean.class);
|
||||
}
|
||||
|
||||
private void lazilyRegisterFeignClientBeanDefinition(String className, Map<String, Object> attributes, BeanDefinitionRegistry registry) {
|
||||
// TODO: verify with prod method
|
||||
private void lazilyRegisterFeignClientBeanDefinition(String className, Map<String, Object> attributes,
|
||||
BeanDefinitionRegistry registry) {
|
||||
ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory
|
||||
? (ConfigurableBeanFactory) registry : null;
|
||||
? (ConfigurableBeanFactory) registry : null;
|
||||
Class clazz = ClassUtils.resolveClassName(className, null);
|
||||
String contextId = getContextId(beanFactory, attributes);
|
||||
String name = getName(attributes);
|
||||
@@ -272,14 +271,6 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
|
||||
factoryBean.setContextId(contextId);
|
||||
factoryBean.setType(clazz);
|
||||
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, () -> {
|
||||
factoryBean.setUrl(getUrl(beanFactory, attributes));
|
||||
factoryBean.setPath(getPath(beanFactory, attributes));
|
||||
@@ -287,18 +278,19 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
|
||||
Object fallback = attributes.get("fallback");
|
||||
if (fallback != null) {
|
||||
factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback
|
||||
: ClassUtils.resolveClassName(fallback.toString(), null));
|
||||
: ClassUtils.resolveClassName(fallback.toString(), null));
|
||||
}
|
||||
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);
|
||||
@@ -308,6 +300,11 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
|
||||
|
||||
beanDefinition.setPrimary(primary);
|
||||
|
||||
String[] qualifiers = getQualifiers(attributes);
|
||||
if (ObjectUtils.isEmpty(qualifiers)) {
|
||||
qualifiers = new String[] { contextId + "FeignClient" };
|
||||
}
|
||||
|
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
|
||||
|
||||
@@ -463,13 +460,14 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo
|
||||
"Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());
|
||||
}
|
||||
|
||||
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object className, Object configuration) {
|
||||
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object className,
|
||||
Object configuration) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
|
||||
builder.addConstructorArgValue(name);
|
||||
builder.addConstructorArgValue(className);
|
||||
builder.addConstructorArgValue(configuration);
|
||||
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
|
||||
builder.getBeanDefinition());
|
||||
builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2022-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.openfeign.aot;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -26,8 +42,8 @@ import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link BeanRegistrationAotProcessor} that creates an {@link BeanRegistrationAotContribution} for
|
||||
* Feign child contexts.
|
||||
* A {@link BeanRegistrationAotProcessor} that creates an
|
||||
* {@link BeanRegistrationAotContribution} for Feign child contexts.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 4.0.0
|
||||
@@ -38,7 +54,6 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
|
||||
|
||||
private final FeignClientFactory feignClientFactory;
|
||||
|
||||
|
||||
public FeignChildContextInitializer(ApplicationContext applicationContext, FeignClientFactory feignClientFactory) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.feignClientFactory = feignClientFactory;
|
||||
@@ -50,13 +65,13 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
|
||||
ConfigurableApplicationContext context = ((ConfigurableApplicationContext) applicationContext);
|
||||
BeanFactory applicationBeanFactory = context.getBeanFactory();
|
||||
if (!((registeredBean.getBeanClass().equals(FeignClientFactory.class))
|
||||
&& registeredBean.getBeanFactory().equals(applicationBeanFactory))) {
|
||||
&& registeredBean.getBeanFactory().equals(applicationBeanFactory))) {
|
||||
return null;
|
||||
}
|
||||
Set<String> contextIds = new HashSet<>(getContextIdsFromConfig());
|
||||
Map<String, GenericApplicationContext> childContextAotContributions = contextIds.stream()
|
||||
.map(contextId -> Map.entry(contextId, buildChildContext(contextId)))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
.map(contextId -> Map.entry(contextId, buildChildContext(contextId)))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
return new AotContribution(childContextAotContributions);
|
||||
}
|
||||
|
||||
@@ -68,51 +83,44 @@ public class FeignChildContextInitializer implements BeanRegistrationAotProcesso
|
||||
|
||||
private Collection<String> getContextIdsFromConfig() {
|
||||
Map<String, FeignClientSpecification> configurations = feignClientFactory.getConfigurations();
|
||||
return configurations.keySet().stream().filter(key -> !key.startsWith("default."))
|
||||
.collect(Collectors.toSet());
|
||||
return configurations.keySet().stream().filter(key -> !key.startsWith("default.")).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
|
||||
private static class AotContribution implements BeanRegistrationAotContribution {
|
||||
|
||||
private final Map<String, GenericApplicationContext> childContexts;
|
||||
|
||||
public AotContribution(Map<String, GenericApplicationContext> childContexts) {
|
||||
this.childContexts = childContexts.entrySet().stream()
|
||||
.filter(entry -> entry.getValue() != null)
|
||||
.map(entry -> Map.entry(entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
AotContribution(Map<String, GenericApplicationContext> childContexts) {
|
||||
this.childContexts = childContexts.entrySet().stream().filter(entry -> entry.getValue() != null)
|
||||
.map(entry -> Map.entry(entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
|
||||
Map<String, ClassName> generatedInitializerClassNames = childContexts.entrySet()
|
||||
.stream()
|
||||
.map(entry -> {
|
||||
String name = entry.getValue().getDisplayName();
|
||||
name = name.replaceAll("[-]", "_");
|
||||
GenerationContext childGenerationContext = generationContext.withName(name);
|
||||
ClassName initializerClassName = new ApplicationContextAotGenerator()
|
||||
Map<String, ClassName> generatedInitializerClassNames = childContexts.entrySet().stream().map(entry -> {
|
||||
String name = entry.getValue().getDisplayName();
|
||||
name = name.replaceAll("[-]", "_");
|
||||
GenerationContext childGenerationContext = generationContext.withName(name);
|
||||
ClassName initializerClassName = new ApplicationContextAotGenerator()
|
||||
.processAheadOfTime(entry.getValue(), childGenerationContext);
|
||||
return Map.entry(entry.getKey(), initializerClassName);
|
||||
})
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
return Map.entry(entry.getKey(), initializerClassName);
|
||||
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
GeneratedMethod postProcessorMethod = beanRegistrationCode.getMethods()
|
||||
.add("addFeignChildContextInitializer",
|
||||
method -> {
|
||||
.add("addFeignChildContextInitializer", method -> {
|
||||
method.addJavadoc("Use AOT child context management initialization")
|
||||
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
|
||||
.addParameter(RegisteredBean.class, "registeredBean")
|
||||
.addParameter(FeignClientFactory.class, "instance")
|
||||
.returns(FeignClientFactory.class)
|
||||
.addStatement("$T<String, Object> initializers = new $T<>()", Map.class, HashMap.class);
|
||||
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
|
||||
.addParameter(RegisteredBean.class, "registeredBean")
|
||||
.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,
|
||||
generatedInitializerClassNames.get(contextId)));
|
||||
.forEach(contextId -> method.addStatement("initializers.put($S, new $L())", contextId,
|
||||
generatedInitializerClassNames.get(contextId)));
|
||||
method.addStatement("return instance.withApplicationContextInitializers(initializers)");
|
||||
});
|
||||
beanRegistrationCode.addInstancePostProcessor(postProcessorMethod.toMethodReference());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2022-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.openfeign.aot;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -37,33 +53,31 @@ import org.springframework.util.ClassUtils;
|
||||
/**
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
public class FeignClientBeanFactoryInitializationAotProcessor implements BeanRegistrationExcludeFilter, BeanFactoryInitializationAotProcessor {
|
||||
|
||||
public class FeignClientBeanFactoryInitializationAotProcessor
|
||||
implements BeanRegistrationExcludeFilter, BeanFactoryInitializationAotProcessor {
|
||||
|
||||
private final GenericApplicationContext context;
|
||||
|
||||
private final Map<String, BeanDefinition> feignClientBeanDefinitions;
|
||||
|
||||
public FeignClientBeanFactoryInitializationAotProcessor(GenericApplicationContext context, FeignClientFactory feignClientFactory) {
|
||||
public FeignClientBeanFactoryInitializationAotProcessor(GenericApplicationContext context,
|
||||
FeignClientFactory feignClientFactory) {
|
||||
this.context = context;
|
||||
this.feignClientBeanDefinitions = getFeignClientBeanDefinitions(feignClientFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) {
|
||||
return registeredBean.getBeanClass()
|
||||
.equals(FeignClientFactoryBean.class) || feignClientBeanDefinitions
|
||||
.containsKey(registeredBean.getBeanClass().getName());
|
||||
return registeredBean.getBeanClass().equals(FeignClientFactoryBean.class)
|
||||
|| feignClientBeanDefinitions.containsKey(registeredBean.getBeanClass().getName());
|
||||
}
|
||||
|
||||
private Map<String, BeanDefinition> getFeignClientBeanDefinitions(FeignClientFactory feignClientFactory) {
|
||||
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));
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,7 +89,7 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg
|
||||
return new AotContribution(feignClientBeanDefinitions);
|
||||
}
|
||||
|
||||
private static class AotContribution implements BeanFactoryInitializationAotContribution {
|
||||
private static final class AotContribution implements BeanFactoryInitializationAotContribution {
|
||||
|
||||
private final Map<String, BeanDefinition> feignClientBeanDefinitions;
|
||||
|
||||
@@ -84,22 +98,23 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTo(GenerationContext generationContext, BeanFactoryInitializationCode beanFactoryInitializationCode) {
|
||||
Set<String> feignClientRegistrationMethods = feignClientBeanDefinitions.values()
|
||||
.stream()
|
||||
.map(beanDefinition -> {
|
||||
Assert.notNull(beanDefinition, "beanDefinition cannot be null");
|
||||
Assert.isInstanceOf(GenericBeanDefinition.class, beanDefinition);
|
||||
GenericBeanDefinition registeredBeanDefinition = (GenericBeanDefinition) beanDefinition;
|
||||
MutablePropertyValues feignClientProperties = registeredBeanDefinition.getPropertyValues();
|
||||
return beanFactoryInitializationCode.getMethods()
|
||||
.add(buildMethodName((String) feignClientProperties.get("type")),
|
||||
method -> generateFeignClientRegistrationMethod(method, feignClientProperties, registeredBeanDefinition))
|
||||
.getName();
|
||||
}).collect(Collectors.toSet());
|
||||
public void applyTo(GenerationContext generationContext,
|
||||
BeanFactoryInitializationCode beanFactoryInitializationCode) {
|
||||
Set<String> feignClientRegistrationMethods = feignClientBeanDefinitions.values().stream()
|
||||
.map(beanDefinition -> {
|
||||
Assert.notNull(beanDefinition, "beanDefinition cannot be null");
|
||||
Assert.isInstanceOf(GenericBeanDefinition.class, beanDefinition);
|
||||
GenericBeanDefinition registeredBeanDefinition = (GenericBeanDefinition) beanDefinition;
|
||||
MutablePropertyValues feignClientProperties = registeredBeanDefinition.getPropertyValues();
|
||||
return beanFactoryInitializationCode.getMethods()
|
||||
.add(buildMethodName((String) feignClientProperties.get("type")),
|
||||
method -> generateFeignClientRegistrationMethod(method, feignClientProperties,
|
||||
registeredBeanDefinition))
|
||||
.getName();
|
||||
}).collect(Collectors.toSet());
|
||||
MethodReference initializerMethod = beanFactoryInitializationCode.getMethods()
|
||||
.add("initialize", method -> generateInitializerMethod(method, feignClientRegistrationMethods))
|
||||
.toMethodReference();
|
||||
.add("initialize", method -> generateInitializerMethod(method, feignClientRegistrationMethods))
|
||||
.toMethodReference();
|
||||
beanFactoryInitializationCode.addInitializer(initializerMethod);
|
||||
}
|
||||
|
||||
@@ -110,37 +125,48 @@ public class FeignClientBeanFactoryInitializationAotProcessor implements BeanReg
|
||||
private void generateInitializerMethod(MethodSpec.Builder method, Set<String> feignClientRegistrationMethods) {
|
||||
method.addModifiers(Modifier.PUBLIC);
|
||||
method.addParameter(DefaultListableBeanFactory.class, "registry");
|
||||
feignClientRegistrationMethods.forEach(feignClientRegistrationMethod -> method.addStatement("$N(registry)", feignClientRegistrationMethod));
|
||||
feignClientRegistrationMethods.forEach(feignClientRegistrationMethod -> method.addStatement("$N(registry)",
|
||||
feignClientRegistrationMethod));
|
||||
}
|
||||
|
||||
private void generateFeignClientRegistrationMethod(MethodSpec.Builder method, MutablePropertyValues feignClientPropertyValues, GenericBeanDefinition registeredBeanDefinition) {
|
||||
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", feignClientPropertyValues.get("type"))
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
.addParameter(BeanDefinitionRegistry.class, "registry")
|
||||
.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() != null ? registeredBeanDefinition.getLazyInit() : false)
|
||||
.addStatement("$T beanDefinition = definition.getBeanDefinition()", AbstractBeanDefinition.class)
|
||||
.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, feignClientPropertyValues.get("type"), qualifiers)
|
||||
.addStatement("$T.registerBeanDefinition(holder, registry) ", BeanDefinitionReaderUtils.class);
|
||||
method.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,
|
||||
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() != null ? registeredBeanDefinition.getLazyInit()
|
||||
: false)
|
||||
.addStatement("$T beanDefinition = definition.getBeanDefinition()", AbstractBeanDefinition.class)
|
||||
.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,
|
||||
feignClientPropertyValues.get("type"), qualifiers)
|
||||
.addStatement("$T.registerBeanDefinition(holder, registry) ", BeanDefinitionReaderUtils.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class FeignClientFactoryTest {
|
||||
}
|
||||
|
||||
private FeignClientSpecification getSpec(String name, String className, Class<?> configClass) {
|
||||
return new FeignClientSpecification(name, className, new Class[] {configClass});
|
||||
return new FeignClientSpecification(name, className, new Class[] { configClass });
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -54,7 +54,8 @@ public class FeignClientFactoryTests {
|
||||
parent.refresh();
|
||||
FeignClientFactory context = new FeignClientFactory();
|
||||
context.setApplicationContext(parent);
|
||||
context.setConfigurations(Arrays.asList(getSpec("foo", null, FooConfig.class), getSpec("bar", null, BarConfig.class)));
|
||||
context.setConfigurations(
|
||||
Arrays.asList(getSpec("foo", null, FooConfig.class), getSpec("bar", null, BarConfig.class)));
|
||||
|
||||
Foo foo = context.getInstance("foo", Foo.class);
|
||||
assertThat(foo).as("foo was null").isNotNull();
|
||||
@@ -77,14 +78,14 @@ public class FeignClientFactoryTests {
|
||||
Proxy target = context.getBean(FeignClientFactoryBean.class).getTarget();
|
||||
Object invocationHandler = ReflectionTestUtils.getField(target, "h");
|
||||
Map<Method, InvocationHandlerFactory.MethodHandler> dispatch = (Map<Method, InvocationHandlerFactory.MethodHandler>) ReflectionTestUtils
|
||||
.getField(invocationHandler, "dispatch");
|
||||
.getField(invocationHandler, "dispatch");
|
||||
Method key = new ArrayList<>(dispatch.keySet()).get(0);
|
||||
Object client = ReflectionTestUtils.getField(dispatch.get(key), "client");
|
||||
assertThat(client).isInstanceOf(Client.Default.class);
|
||||
}
|
||||
|
||||
private FeignClientSpecification getSpec(String name, String className, Class<?> configClass) {
|
||||
return new FeignClientSpecification(name, className, new Class[] {configClass});
|
||||
return new FeignClientSpecification(name, className, new Class[] { configClass });
|
||||
}
|
||||
|
||||
interface TestType {
|
||||
@@ -106,7 +107,7 @@ public class FeignClientFactoryTests {
|
||||
FeignClientFactory feignContext() {
|
||||
FeignClientFactory feignClientFactory = new FeignClientFactory();
|
||||
feignClientFactory.setConfigurations(Collections.singletonList(
|
||||
new FeignClientSpecification("test", null, new Class[] {LoadBalancerAutoConfiguration.class})));
|
||||
new FeignClientSpecification("test", null, new Class[] { LoadBalancerAutoConfiguration.class })));
|
||||
return feignClientFactory;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2022-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.openfeign.aot;
|
||||
|
||||
import java.net.URL;
|
||||
@@ -60,31 +76,31 @@ public class FeignAotTests {
|
||||
@SuppressWarnings("unchecked")
|
||||
void shouldStartFeignChildContextsFromAotContributions(CapturedOutput output) {
|
||||
WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(
|
||||
AnnotationConfigServletWebApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class,
|
||||
FeignAutoConfiguration.class))
|
||||
.withConfiguration(UserConfigurations.of(TestFeignConfiguration.class))
|
||||
.withPropertyValues("logging.level.org.springframework.cloud=DEBUG");
|
||||
AnnotationConfigServletWebApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class,
|
||||
FeignAutoConfiguration.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(
|
||||
(GenericApplicationContext) context.getSourceApplicationContext(), generationContext);
|
||||
(GenericApplicationContext) context.getSourceApplicationContext(), generationContext);
|
||||
generationContext.writeGeneratedContent();
|
||||
TestCompiler compiler = TestCompiler.forSystem();
|
||||
compiler.with(generationContext).compile(compiled -> {
|
||||
ServletWebServerApplicationContext freshApplicationContext = new ServletWebServerApplicationContext();
|
||||
ApplicationContextInitializer<GenericApplicationContext> initializer = compiled
|
||||
.getInstance(ApplicationContextInitializer.class, className.toString());
|
||||
.getInstance(ApplicationContextInitializer.class, className.toString());
|
||||
initializer.initialize(freshApplicationContext);
|
||||
assertThat(output).contains("Creating a FeignClientFactoryBean.");
|
||||
assertThat(output).contains("Refreshing FeignClientFactory-test-with-config",
|
||||
"Refreshing FeignClientFactory-test");
|
||||
"Refreshing FeignClientFactory-test");
|
||||
assertThat(output).doesNotContain("Instantiating bean from Test custom config",
|
||||
"Instantiating bean from default custom config");
|
||||
"Instantiating bean from default custom config");
|
||||
TestPropertyValues.of(AotDetector.AOT_ENABLED + "=true")
|
||||
.applyToSystemProperties(freshApplicationContext::refresh);
|
||||
.applyToSystemProperties(freshApplicationContext::refresh);
|
||||
assertThat(output).contains("Instantiating bean from Test custom config",
|
||||
"Instantiating bean from default custom config");
|
||||
"Instantiating bean from default custom config");
|
||||
assertThat(freshApplicationContext.getBean(TestFeignClient.class)).isNotNull();
|
||||
assertThat(freshApplicationContext.getBean(TestFeignClientWithConfig.class)).isNotNull();
|
||||
});
|
||||
@@ -96,7 +112,8 @@ public class FeignAotTests {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableFeignClients(clients = {TestFeignClient.class, TestFeignClientWithConfig.class}, defaultConfiguration = DefaultConfiguration.class)
|
||||
@EnableFeignClients(clients = { TestFeignClient.class, TestFeignClientWithConfig.class },
|
||||
defaultConfiguration = DefaultConfiguration.class)
|
||||
public static class TestFeignConfiguration {
|
||||
|
||||
@Autowired
|
||||
|
||||
Reference in New Issue
Block a user