Merge remote-tracking branch 'origin/2.2.x'

# Conflicts:
#	spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientProperties.java
This commit is contained in:
Olga Maciaszek-Sharma
2020-10-29 16:54:47 +01:00
5 changed files with 126 additions and 9 deletions

View File

@@ -173,6 +173,10 @@ feign:
loggerLevel: full
errorDecoder: com.example.SimpleErrorDecoder
retryer: com.example.SimpleRetryer
defaultQueryParameters:
query: queryValue
defaultRequestHeaders:
header: headerValue
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
@@ -186,6 +190,8 @@ Default configurations can be specified in the `@EnableFeignClients` attribute `
If you prefer using configuration properties to configured all `@FeignClient`, you can create configuration properties with `default` feign name.
You can use `feign.client.config.feignName.defaultQueryParameters` and `feign.client.config.feignName.defaultRequestHeaders` to specify query parameters and headers that will be sent with every request of the client named `feignName`.
application.yml
[source,yaml]
----

View File

@@ -56,6 +56,7 @@ import org.springframework.util.StringUtils;
* @author Gregor Zurowski
* @author Matt King
* @author Olga Maciaszek-Sharma
* @author Ilia Ilinykh
*/
public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
@@ -237,6 +238,14 @@ public class FeignClientFactoryBean implements FactoryBean<Object>, Initializing
builder.encoder(getOrInstantiate(config.getEncoder()));
}
if (Objects.nonNull(config.getDefaultRequestHeaders())) {
builder.requestInterceptor(requestTemplate -> requestTemplate.headers(config.getDefaultRequestHeaders()));
}
if (Objects.nonNull(config.getDefaultQueryParameters())) {
builder.requestInterceptor(requestTemplate -> requestTemplate.queries(config.getDefaultQueryParameters()));
}
if (Objects.nonNull(config.getDecoder())) {
builder.decoder(getOrInstantiate(config.getDecoder()));
}

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.openfeign;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -34,6 +35,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Eko Kurniawan Khannedy
* @author Ilia Ilinykh
*/
@ConfigurationProperties("feign.client")
public class FeignClientProperties {
@@ -103,6 +105,10 @@ public class FeignClientProperties {
private List<Class<RequestInterceptor>> requestInterceptors;
private Map<String, Collection<String>> defaultRequestHeaders;
private Map<String, Collection<String>> defaultQueryParameters;
private Boolean decode404;
private Class<Decoder> decoder;
@@ -161,6 +167,22 @@ public class FeignClientProperties {
this.requestInterceptors = requestInterceptors;
}
public Map<String, Collection<String>> getDefaultRequestHeaders() {
return defaultRequestHeaders;
}
public void setDefaultRequestHeaders(Map<String, Collection<String>> defaultRequestHeaders) {
this.defaultRequestHeaders = defaultRequestHeaders;
}
public Map<String, Collection<String>> getDefaultQueryParameters() {
return defaultQueryParameters;
}
public void setDefaultQueryParameters(Map<String, Collection<String>> defaultQueryParameters) {
this.defaultQueryParameters = defaultQueryParameters;
}
public Boolean getDecode404() {
return this.decode404;
}
@@ -216,14 +238,17 @@ public class FeignClientProperties {
&& Objects.equals(this.requestInterceptors, that.requestInterceptors)
&& Objects.equals(this.decode404, that.decode404) && Objects.equals(this.encoder, that.encoder)
&& Objects.equals(this.decoder, that.decoder) && Objects.equals(this.contract, that.contract)
&& Objects.equals(this.exceptionPropagationPolicy, that.exceptionPropagationPolicy);
&& Objects.equals(this.exceptionPropagationPolicy, that.exceptionPropagationPolicy)
&& Objects.equals(this.defaultRequestHeaders, that.defaultRequestHeaders)
&& Objects.equals(this.defaultQueryParameters, that.defaultQueryParameters);
}
@Override
public int hashCode() {
return Objects.hash(this.loggerLevel, this.connectTimeout, this.readTimeout, this.retryer,
this.errorDecoder, this.requestInterceptors, this.decode404, this.encoder, this.decoder,
this.contract, this.exceptionPropagationPolicy);
this.contract, this.exceptionPropagationPolicy, this.defaultQueryParameters,
this.defaultRequestHeaders);
}
}

View File

@@ -22,9 +22,15 @@ import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.servlet.http.HttpServletRequest;
@@ -55,8 +61,11 @@ import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
@@ -66,6 +75,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
/**
* @author Eko Kurniawan Khannedy
* @author Olga Maciaszek-Sharma
* @author Ilia Ilinykh
*/
@SuppressWarnings("FieldMayBeFinal")
@RunWith(SpringJUnit4ClassRunner.class)
@@ -91,6 +101,10 @@ public class FeignClientUsingPropertiesTests {
private FeignClientFactoryBean formFactoryBean;
private FeignClientFactoryBean defaultHeadersAndQuerySingleParamsFeignClientFactoryBean;
private FeignClientFactoryBean defaultHeadersAndQueryMultipleParamsFeignClientFactoryBean;
public FeignClientUsingPropertiesTests() {
fooFactoryBean = new FeignClientFactoryBean();
fooFactoryBean.setContextId("foo");
@@ -107,6 +121,14 @@ public class FeignClientUsingPropertiesTests {
formFactoryBean = new FeignClientFactoryBean();
formFactoryBean.setContextId("form");
formFactoryBean.setType(FeignClientFactoryBean.class);
this.defaultHeadersAndQuerySingleParamsFeignClientFactoryBean = new FeignClientFactoryBean();
this.defaultHeadersAndQuerySingleParamsFeignClientFactoryBean.setContextId("singleValue");
this.defaultHeadersAndQuerySingleParamsFeignClientFactoryBean.setType(FeignClientFactoryBean.class);
this.defaultHeadersAndQueryMultipleParamsFeignClientFactoryBean = new FeignClientFactoryBean();
this.defaultHeadersAndQueryMultipleParamsFeignClientFactoryBean.setContextId("multipleValue");
this.defaultHeadersAndQueryMultipleParamsFeignClientFactoryBean.setType(FeignClientFactoryBean.class);
}
public FooClient fooClient() {
@@ -154,6 +176,30 @@ public class FeignClientUsingPropertiesTests {
assertThat(response).isEqualTo("Data");
}
@Test
public void testSingleValue() {
List<String> response = singleValueClient().singleValue();
assertThat(response).isEqualTo(Arrays.asList("header", "parameter"));
}
@Test
public void testMultipleValue() {
List<String> response = multipleValueClient().multipleValue();
assertThat(response).isEqualTo(Arrays.asList("header1", "header2", "parameter1", "parameter2"));
}
public SingleValueClient singleValueClient() {
this.defaultHeadersAndQuerySingleParamsFeignClientFactoryBean.setApplicationContext(this.applicationContext);
return this.defaultHeadersAndQuerySingleParamsFeignClientFactoryBean.feign(this.context)
.target(SingleValueClient.class, "http://localhost:" + this.port);
}
public MultipleValueClient multipleValueClient() {
this.defaultHeadersAndQueryMultipleParamsFeignClientFactoryBean.setApplicationContext(this.applicationContext);
return this.defaultHeadersAndQueryMultipleParamsFeignClientFactoryBean.feign(this.context)
.target(MultipleValueClient.class, "http://localhost:" + this.port);
}
@Test
public void readTimeoutShouldWorkWhenConnectTimeoutNotSet() {
FeignClientFactoryBean readTimeoutFactoryBean = new FeignClientFactoryBean();
@@ -196,21 +242,21 @@ public class FeignClientUsingPropertiesTests {
protected interface FooClient {
@RequestMapping(method = RequestMethod.GET, value = "/foo")
@GetMapping(path = "/foo")
String foo();
}
protected interface BarClient {
@RequestMapping(method = RequestMethod.GET, value = "/bar")
@GetMapping(path = "/bar")
String bar();
}
protected interface UnwrapClient {
@RequestMapping(method = RequestMethod.GET, value = "/bar") // intentionally /bar
@GetMapping(path = "/bar") // intentionally /bar
String unwrap() throws IOException;
}
@@ -223,6 +269,20 @@ public class FeignClientUsingPropertiesTests {
}
protected interface SingleValueClient {
@GetMapping(path = "/singleValue")
List<String> singleValue();
}
protected interface MultipleValueClient {
@GetMapping(path = "/multipleValue")
List<String> multipleValue();
}
protected interface TimeoutClient {
@GetMapping("/timeouts")
@@ -246,18 +306,31 @@ public class FeignClientUsingPropertiesTests {
}
}
@RequestMapping(method = RequestMethod.GET, value = "/bar")
@GetMapping(path = "/bar")
public String bar() throws InterruptedException {
Thread.sleep(2000L);
TimeUnit.SECONDS.sleep(2);
return "OK";
}
@RequestMapping(value = "/form", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@PostMapping(path = "/form", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String form(HttpServletRequest request) {
return request.getParameter("form");
}
@GetMapping(path = "/singleValue")
public List<String> singleValue(@RequestHeader List<String> singleValueHeaders,
@RequestParam List<String> singleValueParameters) {
return Stream.of(singleValueHeaders, singleValueParameters).flatMap(Collection::stream)
.collect(Collectors.toList());
}
@GetMapping(path = "/multipleValue")
public List<String> multipleValue(@RequestHeader List<String> multipleValueHeaders,
@RequestParam List<String> multipleValueParameters) {
return Stream.of(multipleValueHeaders, multipleValueParameters).flatMap(Collection::stream)
.collect(Collectors.toList());
}
}
public static class FooRequestInterceptor implements RequestInterceptor {

View File

@@ -10,6 +10,10 @@ feign.client.config.default.retryer=org.springframework.cloud.openfeign.FeignCli
feign.client.config.default.decode404=true
feign.client.config.foo.requestInterceptors[0]=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.FooRequestInterceptor
feign.client.config.foo.requestInterceptors[1]=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.BarRequestInterceptor
feign.client.config.singleValue.defaultRequestHeaders[singleValueHeaders]=header
feign.client.config.singleValue.defaultQueryParameters[singleValueParameters]=parameter
feign.client.config.multipleValue.defaultRequestHeaders[multipleValueHeaders]=header1,header2
feign.client.config.multipleValue.defaultQueryParameters[multipleValueParameters]=parameter1,parameter2
feign.client.config.bar.connectTimeout=1000
feign.client.config.bar.readTimeout=1000
feign.client.config.form.encoder=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.FormEncoder