Browse Source

Fix checkstyle. Reformat.

aot-support
Olga Maciaszek-Sharma 2 years ago
parent
commit
b7c43f02c1
  1. 8
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java
  2. 14
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactory.java
  3. 2
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactoryBean.java
  4. 18
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientSpecification.java
  5. 54
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsRegistrar.java
  6. 74
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/aot/FeignChildContextInitializer.java
  7. 132
      spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/aot/FeignClientBeanFactoryInitializationAotProcessor.java
  8. 2
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientFactoryTest.java
  9. 9
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientFactoryTests.java
  10. 41
      spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/aot/FeignAotTests.java

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

@ -113,13 +113,13 @@ public class FeignAutoConfiguration { @@ -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 { @@ -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 {

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

@ -44,7 +44,8 @@ public class FeignClientFactory extends NamedContextFactory<FeignClientSpecifica @@ -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 @@ -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 @@ -89,5 +89,5 @@ public class FeignClientFactory extends NamedContextFactory<FeignClientSpecifica
// Ensure the contexts are only initialized once after Aot processing
applicationContextInitializers = new HashMap<>();
}
}
}

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

@ -419,7 +419,7 @@ public class FeignClientFactoryBean @@ -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)) {

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

@ -68,9 +68,14 @@ public class FeignClientSpecification implements NamedContextFactory.Specificati @@ -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 @@ -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) + "}";
}
}

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

@ -192,7 +192,7 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLo @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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

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

@ -1,3 +1,19 @@ @@ -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; @@ -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 @@ -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 @@ -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 @@ -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());
}
}
}

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

@ -1,3 +1,19 @@ @@ -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; @@ -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 @@ -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 @@ -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 @@ -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);
}
}
}

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

@ -47,7 +47,7 @@ class FeignClientFactoryTest { @@ -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

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

@ -54,7 +54,8 @@ public class FeignClientFactoryTests { @@ -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 { @@ -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 { @@ -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;
}

41
spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/aot/FeignAotTests.java

@ -1,3 +1,19 @@ @@ -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 { @@ -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 { @@ -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

Loading…
Cancel
Save