Add FeignChildContextInitializer.
This commit is contained in:
@@ -191,6 +191,11 @@
|
||||
<version>2.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-client</artifactId>
|
||||
|
||||
@@ -25,7 +25,7 @@ import feign.Target;
|
||||
class DefaultTargeter implements Targeter {
|
||||
|
||||
@Override
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignClientFactory context,
|
||||
Target.HardCodedTarget<T> target) {
|
||||
return feign.target(target);
|
||||
}
|
||||
|
||||
@@ -55,11 +55,13 @@ import org.springframework.cache.interceptor.CacheInterceptor;
|
||||
import org.springframework.cloud.client.actuator.HasFeatures;
|
||||
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
|
||||
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
|
||||
import org.springframework.cloud.openfeign.aot.FeignChildContextInitializer;
|
||||
import org.springframework.cloud.openfeign.security.OAuth2AccessTokenInterceptor;
|
||||
import org.springframework.cloud.openfeign.support.FeignEncoderProperties;
|
||||
import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
|
||||
import org.springframework.cloud.openfeign.support.PageJacksonModule;
|
||||
import org.springframework.cloud.openfeign.support.SortJacksonModule;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -102,12 +104,18 @@ public class FeignAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FeignContext feignContext() {
|
||||
FeignContext context = new FeignContext();
|
||||
public FeignClientFactory feignContext() {
|
||||
FeignClientFactory context = new FeignClientFactory();
|
||||
context.setConfigurations(this.configurations);
|
||||
return context;
|
||||
}
|
||||
|
||||
@Bean
|
||||
static FeignChildContextInitializer feignChildContextInitializer(ApplicationContext parentContext,
|
||||
FeignClientFactory feignClientFactory) {
|
||||
return new FeignChildContextInitializer(parentContext, feignClientFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "spring.cloud.openfeign.cache.enabled", matchIfMissing = true)
|
||||
@ConditionalOnBean(CacheInterceptor.class)
|
||||
@@ -116,7 +124,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 {
|
||||
|
||||
@@ -39,7 +39,7 @@ class FeignCircuitBreakerTargeter implements Targeter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignClientFactory context,
|
||||
Target.HardCodedTarget<T> target) {
|
||||
if (!(feign instanceof FeignCircuitBreaker.Builder builder)) {
|
||||
return feign.target(target);
|
||||
@@ -56,20 +56,20 @@ class FeignCircuitBreakerTargeter implements Targeter {
|
||||
return builder(name, builder).target(target);
|
||||
}
|
||||
|
||||
private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
|
||||
private <T> T targetWithFallbackFactory(String feignClientName, FeignClientFactory context,
|
||||
Target.HardCodedTarget<T> target, FeignCircuitBreaker.Builder builder, Class<?> fallbackFactoryClass) {
|
||||
FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext("fallbackFactory",
|
||||
feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
|
||||
return builder(feignClientName, builder).target(target, fallbackFactory);
|
||||
}
|
||||
|
||||
private <T> T targetWithFallback(String feignClientName, FeignContext context, Target.HardCodedTarget<T> target,
|
||||
FeignCircuitBreaker.Builder builder, Class<?> fallback) {
|
||||
private <T> T targetWithFallback(String feignClientName, FeignClientFactory context,
|
||||
Target.HardCodedTarget<T> target, FeignCircuitBreaker.Builder builder, Class<?> fallback) {
|
||||
T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
|
||||
return builder(feignClientName, builder).target(target, fallbackInstance);
|
||||
}
|
||||
|
||||
private <T> T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context,
|
||||
private <T> T getFromContext(String fallbackMechanism, String feignClientName, FeignClientFactory context,
|
||||
Class<?> beanType, Class<T> targetType) {
|
||||
Object fallbackInstance = context.getInstance(feignClientName, beanType);
|
||||
if (fallbackInstance == null) {
|
||||
|
||||
@@ -31,10 +31,11 @@ import org.springframework.lang.Nullable;
|
||||
* @author Dave Syer
|
||||
* @author Matt King
|
||||
* @author Jasbir Singh
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
|
||||
public class FeignClientFactory extends NamedContextFactory<FeignClientSpecification> {
|
||||
|
||||
public FeignContext() {
|
||||
public FeignClientFactory() {
|
||||
super(FeignClientsConfiguration.class, "spring.cloud.openfeign", "spring.cloud.openfeign.client.name");
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class FeignClientFactoryBean
|
||||
Assert.hasText(name, "Name must be set");
|
||||
}
|
||||
|
||||
protected Feign.Builder feign(FeignContext context) {
|
||||
protected Feign.Builder feign(FeignClientFactory context) {
|
||||
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
|
||||
Logger logger = loggerFactory.create(type);
|
||||
|
||||
@@ -137,7 +137,7 @@ public class FeignClientFactoryBean
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void applyBuildCustomizers(FeignContext context, Feign.Builder builder) {
|
||||
private void applyBuildCustomizers(FeignClientFactory context, Feign.Builder builder) {
|
||||
Map<String, FeignBuilderCustomizer> customizerMap = context.getInstances(contextId,
|
||||
FeignBuilderCustomizer.class);
|
||||
|
||||
@@ -148,7 +148,7 @@ public class FeignClientFactoryBean
|
||||
additionalCustomizers.forEach(customizer -> customizer.customize(builder));
|
||||
}
|
||||
|
||||
protected void configureFeign(FeignContext context, Feign.Builder builder) {
|
||||
protected void configureFeign(FeignClientFactory context, Feign.Builder builder) {
|
||||
FeignClientProperties properties = beanFactory != null ? beanFactory.getBean(FeignClientProperties.class)
|
||||
: applicationContext.getBean(FeignClientProperties.class);
|
||||
|
||||
@@ -172,7 +172,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
}
|
||||
|
||||
protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) {
|
||||
protected void configureUsingConfiguration(FeignClientFactory context, Feign.Builder builder) {
|
||||
Logger.Level level = getInheritedAwareOptional(context, Logger.Level.class);
|
||||
if (level != null) {
|
||||
builder.logLevel(level);
|
||||
@@ -340,7 +340,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> T get(FeignContext context, Class<T> type) {
|
||||
protected <T> T get(FeignClientFactory context, Class<T> type) {
|
||||
T instance = context.getInstance(contextId, type);
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("No bean found of type " + type + " for " + contextId);
|
||||
@@ -348,11 +348,11 @@ public class FeignClientFactoryBean
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected <T> T getOptional(FeignContext context, Class<T> type) {
|
||||
protected <T> T getOptional(FeignClientFactory context, Class<T> type) {
|
||||
return context.getInstance(contextId, type);
|
||||
}
|
||||
|
||||
protected <T> T getInheritedAwareOptional(FeignContext context, Class<T> type) {
|
||||
protected <T> T getInheritedAwareOptional(FeignClientFactory context, Class<T> type) {
|
||||
if (inheritParentContext) {
|
||||
return getOptional(context, type);
|
||||
}
|
||||
@@ -361,7 +361,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> Map<String, T> getInheritedAwareInstances(FeignContext context, Class<T> type) {
|
||||
protected <T> Map<String, T> getInheritedAwareInstances(FeignClientFactory context, Class<T> type) {
|
||||
if (inheritParentContext) {
|
||||
return context.getInstances(contextId, type);
|
||||
}
|
||||
@@ -370,7 +370,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) {
|
||||
protected <T> T loadBalance(Feign.Builder builder, FeignClientFactory context, HardCodedTarget<T> target) {
|
||||
Client client = getOptional(context, Client.class);
|
||||
if (client != null) {
|
||||
builder.client(client);
|
||||
@@ -389,7 +389,7 @@ public class FeignClientFactoryBean
|
||||
* @param contextId name of feign client
|
||||
* @return returns Options found in context
|
||||
*/
|
||||
protected Request.Options getOptionsByName(FeignContext context, String contextId) {
|
||||
protected Request.Options getOptionsByName(FeignClientFactory context, String contextId) {
|
||||
if (refreshableClient) {
|
||||
return context.getInstance(contextId, Request.Options.class.getCanonicalName() + "-" + contextId,
|
||||
Request.Options.class);
|
||||
@@ -409,8 +409,8 @@ public class FeignClientFactoryBean
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> T getTarget() {
|
||||
FeignContext context = beanFactory != null ? beanFactory.getBean(FeignContext.class)
|
||||
: applicationContext.getBean(FeignContext.class);
|
||||
FeignClientFactory context = beanFactory != null ? beanFactory.getBean(FeignClientFactory.class)
|
||||
: applicationContext.getBean(FeignClientFactory.class);
|
||||
Feign.Builder builder = feign(context);
|
||||
if (!StringUtils.hasText(url) && !isUrlAvailableInConfig(contextId)) {
|
||||
|
||||
@@ -468,7 +468,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private <T> HardCodedTarget<T> resolveTarget(FeignContext context, String contextId, String url) {
|
||||
private <T> HardCodedTarget<T> resolveTarget(FeignClientFactory context, String contextId, String url) {
|
||||
if (StringUtils.hasText(url)) {
|
||||
return new HardCodedTarget(type, name, url);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import feign.Target;
|
||||
*/
|
||||
public interface Targeter {
|
||||
|
||||
<T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
|
||||
<T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignClientFactory context,
|
||||
Target.HardCodedTarget<T> target);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
package org.springframework.cloud.openfeign.aot;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
import org.springframework.aot.generate.GeneratedMethod;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
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;
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link BeanRegistrationAotProcessor} that creates an {@link BeanRegistrationAotContribution} for
|
||||
* Feign child contexts.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class FeignChildContextInitializer implements BeanRegistrationAotProcessor, ApplicationListener<WebServerInitializedEvent> {
|
||||
|
||||
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
|
||||
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
|
||||
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
|
||||
ConfigurableApplicationContext context = ((ConfigurableApplicationContext) applicationContext);
|
||||
BeanFactory applicationBeanFactory = context.getBeanFactory();
|
||||
if (!(registeredBean.getBeanClass().equals(getClass())
|
||||
&& 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));
|
||||
return new AotContribution(childContextAotContributions);
|
||||
}
|
||||
|
||||
private GenericApplicationContext buildChildContext(String contextId) {
|
||||
GenericApplicationContext childContext = feignClientFactory.buildContext(contextId);
|
||||
feignClientFactory.registerBeans(contextId, childContext);
|
||||
return childContext;
|
||||
}
|
||||
|
||||
private Collection<String> getContextIdsFromConfig() {
|
||||
Map<String, FeignClientSpecification> configurations = feignClientFactory.getConfigurations();
|
||||
return configurations.keySet().stream().filter(key -> !key.startsWith("default."))
|
||||
.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 {
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@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()
|
||||
.processAheadOfTime(entry.getValue(), childGenerationContext);
|
||||
return Map.entry(entry.getKey(), initializerClassName);
|
||||
})
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
GeneratedMethod postProcessorMethod = beanRegistrationCode.getMethods()
|
||||
.add("addFeignChildContextInitializer",
|
||||
method -> {
|
||||
method.addJavadoc("Use AOT child context management initialization")
|
||||
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
|
||||
.addParameter(RegisteredBean.class, "registeredBean")
|
||||
.addParameter(FeignChildContextInitializer.class, "instance")
|
||||
.returns(FeignChildContextInitializer.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)));
|
||||
method.addStatement("return instance.withApplicationContextInitializers(initializers)");
|
||||
});
|
||||
beanRegistrationCode.addInstancePostProcessor(postProcessorMethod.toMethodReference());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,11 +34,11 @@ import org.springframework.test.annotation.DirtiesContext;
|
||||
class EnableFeignClientsSpringDataTests {
|
||||
|
||||
@Autowired
|
||||
private FeignContext feignContext;
|
||||
private FeignClientFactory feignClientFactory;
|
||||
|
||||
@Test
|
||||
void encoderDefaultCorrect() {
|
||||
PageableSpringEncoder.class.cast(this.feignContext.getInstance("foo", Encoder.class));
|
||||
PageableSpringEncoder.class.cast(this.feignClientFactory.getInstance("foo", Encoder.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
||||
@@ -162,8 +162,8 @@ class FeignBuilderCustomizerTests {
|
||||
protected static class SampleConfiguration2 {
|
||||
|
||||
@Bean
|
||||
FeignContext feignContext() {
|
||||
return new FeignContext();
|
||||
FeignClientFactory feignContext() {
|
||||
return new FeignClientFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -198,8 +198,8 @@ class FeignBuilderCustomizerTests {
|
||||
protected static class SampleConfiguration3 {
|
||||
|
||||
@Bean
|
||||
FeignContext feignContext() {
|
||||
return new FeignContext();
|
||||
FeignClientFactory feignContext() {
|
||||
return new FeignClientFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -158,7 +158,8 @@ class FeignClientBuilderTests {
|
||||
@Test
|
||||
void forType_build() {
|
||||
// given:
|
||||
Mockito.when(this.applicationContext.getBean(FeignContext.class)).thenThrow(new ClosedFileSystemException()); // throw
|
||||
Mockito.when(this.applicationContext.getBean(FeignClientFactory.class))
|
||||
.thenThrow(new ClosedFileSystemException()); // throw
|
||||
// an
|
||||
// unusual
|
||||
// exception
|
||||
|
||||
@@ -46,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class FeignClientDisabledClientLevelFeaturesTests {
|
||||
|
||||
@Autowired
|
||||
private FeignContext context;
|
||||
private FeignClientFactory context;
|
||||
|
||||
@Autowired
|
||||
private FooClient foo;
|
||||
|
||||
@@ -45,7 +45,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class FeignClientDisabledFeaturesTests {
|
||||
|
||||
@Autowired
|
||||
private FeignContext context;
|
||||
private FeignClientFactory context;
|
||||
|
||||
@Autowired
|
||||
private FooClient foo;
|
||||
|
||||
@@ -50,7 +50,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class FeignClientErrorDecoderTests {
|
||||
|
||||
@Autowired
|
||||
private FeignContext context;
|
||||
private FeignClientFactory context;
|
||||
|
||||
@Autowired
|
||||
private FooClient foo;
|
||||
|
||||
@@ -30,18 +30,18 @@ import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class FeignContextTest {
|
||||
class FeignClientFactoryTest {
|
||||
|
||||
@Test
|
||||
void getInstanceWithoutAncestors_verifyNullForMissing() {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
parent.refresh();
|
||||
|
||||
FeignContext feignContext = new FeignContext();
|
||||
feignContext.setApplicationContext(parent);
|
||||
feignContext.setConfigurations(Lists.newArrayList(getSpec("empty", EmptyConfiguration.class)));
|
||||
FeignClientFactory feignClientFactory = new FeignClientFactory();
|
||||
feignClientFactory.setApplicationContext(parent);
|
||||
feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("empty", EmptyConfiguration.class)));
|
||||
|
||||
Logger.Level level = feignContext.getInstanceWithoutAncestors("empty", Logger.Level.class);
|
||||
Logger.Level level = feignClientFactory.getInstanceWithoutAncestors("empty", Logger.Level.class);
|
||||
|
||||
assertThat(level).as("Logger was not null").isNull();
|
||||
}
|
||||
@@ -55,11 +55,11 @@ class FeignContextTest {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
parent.refresh();
|
||||
|
||||
FeignContext feignContext = new FeignContext();
|
||||
feignContext.setApplicationContext(parent);
|
||||
feignContext.setConfigurations(Lists.newArrayList(getSpec("empty", EmptyConfiguration.class)));
|
||||
FeignClientFactory feignClientFactory = new FeignClientFactory();
|
||||
feignClientFactory.setApplicationContext(parent);
|
||||
feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("empty", EmptyConfiguration.class)));
|
||||
|
||||
Collection<RequestInterceptor> interceptors = feignContext
|
||||
Collection<RequestInterceptor> interceptors = feignClientFactory
|
||||
.getInstancesWithoutAncestors("empty", RequestInterceptor.class).values();
|
||||
|
||||
assertThat(interceptors).as("Interceptors is not empty").isEmpty();
|
||||
@@ -70,11 +70,11 @@ class FeignContextTest {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
parent.refresh();
|
||||
|
||||
FeignContext feignContext = new FeignContext();
|
||||
feignContext.setApplicationContext(parent);
|
||||
feignContext.setConfigurations(Lists.newArrayList(getSpec("demo", DemoConfiguration.class)));
|
||||
FeignClientFactory feignClientFactory = new FeignClientFactory();
|
||||
feignClientFactory.setApplicationContext(parent);
|
||||
feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("demo", DemoConfiguration.class)));
|
||||
|
||||
Logger.Level level = feignContext.getInstanceWithoutAncestors("demo", Logger.Level.class);
|
||||
Logger.Level level = feignClientFactory.getInstanceWithoutAncestors("demo", Logger.Level.class);
|
||||
|
||||
assertThat(level).isEqualTo(Logger.Level.FULL);
|
||||
}
|
||||
@@ -84,11 +84,11 @@ class FeignContextTest {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
parent.refresh();
|
||||
|
||||
FeignContext feignContext = new FeignContext();
|
||||
feignContext.setApplicationContext(parent);
|
||||
feignContext.setConfigurations(Lists.newArrayList(getSpec("demo", DemoConfiguration.class)));
|
||||
FeignClientFactory feignClientFactory = new FeignClientFactory();
|
||||
feignClientFactory.setApplicationContext(parent);
|
||||
feignClientFactory.setConfigurations(Lists.newArrayList(getSpec("demo", DemoConfiguration.class)));
|
||||
|
||||
Collection<RequestInterceptor> interceptors = feignContext
|
||||
Collection<RequestInterceptor> interceptors = feignClientFactory
|
||||
.getInstancesWithoutAncestors("demo", RequestInterceptor.class).values();
|
||||
|
||||
assertThat(interceptors.size()).isEqualTo(1);
|
||||
@@ -52,7 +52,7 @@ public class FeignClientFactoryTests {
|
||||
public void testChildContexts() {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
parent.refresh();
|
||||
FeignContext context = new FeignContext();
|
||||
FeignClientFactory context = new FeignClientFactory();
|
||||
context.setApplicationContext(parent);
|
||||
context.setConfigurations(Arrays.asList(getSpec("foo", FooConfig.class), getSpec("bar", BarConfig.class)));
|
||||
|
||||
@@ -103,11 +103,11 @@ public class FeignClientFactoryTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
FeignContext feignContext() {
|
||||
FeignContext feignContext = new FeignContext();
|
||||
feignContext.setConfigurations(Collections.singletonList(
|
||||
FeignClientFactory feignContext() {
|
||||
FeignClientFactory feignClientFactory = new FeignClientFactory();
|
||||
feignClientFactory.setConfigurations(Collections.singletonList(
|
||||
new FeignClientSpecification("test", new Class[] { LoadBalancerAutoConfiguration.class })));
|
||||
return feignContext;
|
||||
return feignClientFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -63,7 +63,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
class FeignClientOverrideDefaultsTests {
|
||||
|
||||
@Autowired
|
||||
private FeignContext context;
|
||||
private FeignClientFactory context;
|
||||
|
||||
@Autowired
|
||||
private FooClient foo;
|
||||
|
||||
@@ -55,7 +55,7 @@ class FeignClientUsingConfigurerTest {
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Autowired
|
||||
private FeignContext context;
|
||||
private FeignClientFactory context;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Test
|
||||
|
||||
@@ -87,7 +87,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
public class FeignClientUsingPropertiesTests {
|
||||
|
||||
@Autowired
|
||||
FeignContext context;
|
||||
FeignClientFactory context;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@@ -47,8 +47,8 @@ class FeignCompressionTests {
|
||||
FeignContentGzipEncodingAutoConfiguration.class,
|
||||
FeignAcceptGzipEncodingAutoConfiguration.class))
|
||||
.run(context -> {
|
||||
FeignContext feignContext = context.getBean(FeignContext.class);
|
||||
Map<String, RequestInterceptor> interceptors = feignContext.getInstances("foo",
|
||||
FeignClientFactory feignClientFactory = context.getBean(FeignClientFactory.class);
|
||||
Map<String, RequestInterceptor> interceptors = feignClientFactory.getInstances("foo",
|
||||
RequestInterceptor.class);
|
||||
assertThat(interceptors.size()).isEqualTo(2);
|
||||
assertThat(interceptors.get("feignAcceptGzipEncodingInterceptor"))
|
||||
|
||||
@@ -153,7 +153,7 @@ class FeignHttpClientUrlTests {
|
||||
public Targeter feignTargeter() {
|
||||
return new Targeter() {
|
||||
@Override
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignClientFactory context,
|
||||
Target.HardCodedTarget<T> target) {
|
||||
Field field = ReflectionUtils.findField(Feign.Builder.class, "client");
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
|
||||
@@ -154,7 +154,7 @@ class FeignHttpClientUrlWithRetryableLoadBalancerTests {
|
||||
public Targeter feignTargeter() {
|
||||
return new Targeter() {
|
||||
@Override
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignClientFactory context,
|
||||
Target.HardCodedTarget<T> target) {
|
||||
Field field = ReflectionUtils.findField(Feign.Builder.class, "client");
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
|
||||
@@ -50,7 +50,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class GzipDecodingTests extends FeignClientFactoryBean {
|
||||
|
||||
@Autowired
|
||||
FeignContext context;
|
||||
FeignClientFactory context;
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port = 0;
|
||||
|
||||
@@ -53,7 +53,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class SpringDecoderTests extends FeignClientFactoryBean {
|
||||
|
||||
@Autowired
|
||||
FeignContext context;
|
||||
FeignClientFactory context;
|
||||
|
||||
@LocalServerPort
|
||||
private int port = 0;
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package org.springframework.cloud.openfeign.aot;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.aot.test.generate.TestGenerationContext;
|
||||
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.web.servlet.context.AnnotationConfigServletWebApplicationContext;
|
||||
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.aot.ApplicationContextAotGenerator;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link FeignChildContextInitializer}.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class FeignChildContextInitializerTests {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(FeignChildContextInitializerTests.class);
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void reset() {
|
||||
ReflectionTestUtils.setField(TomcatURLStreamHandlerFactory.class, "instance", null);
|
||||
ReflectionTestUtils.setField(URL.class, "factory", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@CompileWithForkedClassLoader
|
||||
@SuppressWarnings("unchecked")
|
||||
void shouldStartFeignChildContextsFromAotContributions(CapturedOutput output) {
|
||||
WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(
|
||||
AnnotationConfigServletWebApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class,
|
||||
FeignAutoConfiguration.class))
|
||||
.withConfiguration(UserConfigurations.of(TestFeignConfiguration.class));
|
||||
contextRunner.prepare(context -> {
|
||||
TestGenerationContext generationContext = new TestGenerationContext(TestTarget.class);
|
||||
ClassName className = new ApplicationContextAotGenerator().processAheadOfTime(
|
||||
(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());
|
||||
initializer.initialize(freshApplicationContext);
|
||||
assertThat(output).isNotEmpty();
|
||||
|
||||
// TODO
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static class TestTarget {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableFeignClients(clients = {TestFeignClient.class, TestFeignClientWithConfig.class}, defaultConfiguration = DefaultConfiguration.class)
|
||||
public static class TestFeignConfiguration {
|
||||
|
||||
}
|
||||
|
||||
public static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
TestBean testBean() {
|
||||
LOG.debug("Instantiating bean from Test custom config");
|
||||
return new TestBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DefaultConfiguration {
|
||||
|
||||
@Bean
|
||||
TestBean defaultTestBean() {
|
||||
LOG.debug("Instantiating bean from default custom config");
|
||||
return new TestBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TestBean {
|
||||
|
||||
}
|
||||
|
||||
@FeignClient("test")
|
||||
interface TestFeignClient {
|
||||
|
||||
void test();
|
||||
|
||||
}
|
||||
|
||||
// TODO: verify other annotation parameters
|
||||
@FeignClient(value = "test-with-config", configuration = TestConfiguration.class)
|
||||
interface TestFeignClientWithConfig {
|
||||
|
||||
void test();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.openfeign.FeignContext;
|
||||
import org.springframework.cloud.openfeign.FeignClientFactory;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -51,7 +51,7 @@ class PageableEncoderTests {
|
||||
public static final String SORT_1 = "sort1";
|
||||
|
||||
@Autowired
|
||||
private FeignContext context;
|
||||
private FeignClientFactory context;
|
||||
|
||||
protected String getPageParameter() {
|
||||
return "page";
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.openfeign.FeignContext;
|
||||
import org.springframework.cloud.openfeign.FeignClientFactory;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -52,7 +52,7 @@ class PageableSpringQueryMapEncoderTests {
|
||||
public static final String SORT_1 = "sort1";
|
||||
|
||||
@Autowired
|
||||
private FeignContext context;
|
||||
private FeignClientFactory context;
|
||||
|
||||
protected String getPageParameter() {
|
||||
return "page";
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.openfeign.FeignContext;
|
||||
import org.springframework.cloud.openfeign.FeignClientFactory;
|
||||
import org.springframework.cloud.openfeign.encoding.HttpEncoding;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -77,7 +77,7 @@ import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;
|
||||
class SpringEncoderTests {
|
||||
|
||||
@Autowired
|
||||
private FeignContext context;
|
||||
private FeignClientFactory context;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myHttpMessageConverter")
|
||||
|
||||
Reference in New Issue
Block a user