Compare commits

...
12 Commits
15 changed files with 132 additions and 65 deletions
-38
View File
@@ -1,38 +0,0 @@
version: 2
jobs:
build:
docker:
- image: springcloud/pipeline-base
environment:
_JAVA_OPTIONS: "-Xms1024m -Xmx2048m"
TERM: dumb
branches:
ignore:
- gh-pages # list of branches to ignore
steps:
- checkout
- restore_cache:
key: sc-openfeign-{{ .Branch }}
- run:
name: "Download dependencies"
command: ./mvnw -s .settings.xml -U --fail-never dependency:go-offline || true
- save_cache:
key: sc-openfeign-{{ .Branch }}
paths:
- ~/.m2
- run:
name: "Running build"
command: ./mvnw -s .settings.xml clean org.jacoco:jacoco-maven-plugin:prepare-agent install -U -P sonar -nsu --batch-mode -Dmaven.test.redirectTestOutputToFile=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
- run:
name: "Aggregate test results"
when: always
command: |
mkdir -p $CIRCLE_TEST_REPORTS/junit/
find . -type f -regex ".*/target/.*-reports/.*" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
bash <(curl -s https://codecov.io/bash)
- store_artifacts:
path: /junit/
destination: artifacts
- store_test_results:
path: /junit/
destination: testartifacts
+35
View File
@@ -0,0 +1,35 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Build
on:
push:
branches: [ 2.2.x ]
pull_request:
branches: [ 2.2.x ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
java: ["8", "11", "16"]
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Cache local Maven repository
uses: actions/cache@v2
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build with Maven
run: ./mvnw clean install -B -U
+1 -1
View File
@@ -5,7 +5,7 @@ Edit the files in the src/main/asciidoc/ directory instead.
////
image:https://circleci.com/gh/spring-cloud/spring-cloud-openfeign.svg?style=svg["CircleCI", link="https://circleci.com/gh/spring-cloud/spring-cloud-openfeign"]
image::https://github.com/spring-cloud/spring-cloud-openfeign/workflows/Build/badge.svg?branch=2.2.x&style=svg["Build",link="https://github.com/spring-cloud/spring-cloud-openfeign/actions"]
image:https://codecov.io/gh/spring-cloud/spring-cloud-openfeign/branch/master/graph/badge.svg["Codecov", link="https://codecov.io/gh/spring-cloud/spring-cloud-openfeign"]
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign</artifactId>
<version>2.2.8.BUILD-SNAPSHOT</version>
<version>2.2.8.RELEASE</version>
</parent>
<artifactId>spring-cloud-openfeign-docs</artifactId>
<packaging>pom</packaging>
+1 -1
View File
@@ -1,4 +1,4 @@
image:https://circleci.com/gh/spring-cloud/spring-cloud-openfeign.svg?style=svg["CircleCI", link="https://circleci.com/gh/spring-cloud/spring-cloud-openfeign"]
image::https://github.com/spring-cloud/spring-cloud-openfeign/workflows/Build/badge.svg?branch=2.2.x&style=svg["Build",link="https://github.com/spring-cloud/spring-cloud-openfeign/actions"]
image:https://codecov.io/gh/spring-cloud/spring-cloud-openfeign/branch/master/graph/badge.svg["Codecov", link="https://codecov.io/gh/spring-cloud/spring-cloud-openfeign"]
+7 -6
View File
@@ -18,15 +18,16 @@
|feign.httpclient.disable-ssl-validation | `false` |
|feign.httpclient.enabled | `true` | Enables the use of the Apache HTTP Client by Feign.
|feign.httpclient.follow-redirects | `true` |
|feign.httpclient.hc5.enabled | `false` | Enables the use of the Apache HTTP Client 5 by Feign.
|feign.httpclient.hc5.pool-concurrency-policy | | Pool concurrency policies.
|feign.httpclient.hc5.pool-reuse-policy | | Pool connection re-use policies.
|feign.httpclient.hc5.socket-timeout | `5` | Default value for socket timeout.
|feign.httpclient.hc5.socket-timeout-unit | | Default value for socket timeout unit.
|feign.httpclient.max-connections | `200` |
|feign.httpclient.max-connections-per-route | `50` |
|feign.httpclient.time-to-live | `900` |
|feign.httpclient.time-to-live-unit | |
|feign.hystrix.enabled | `false` | If true, an OpenFeign client will be wrapped with a Hystrix circuit breaker.
|feign.okhttp.enabled | `false` | Enables the use of the OK HTTP Client by Feign.
|feign.httpclient.hc5.enabled | `false` | Enables the use of the Apache HC5 by Feign.
|feign.httpclient.hc5.socket-timeout | `5` |
|feign.httpclient.hc5.socket-timeout-unit | `seconds` |
|feign.httpclient.hc5.pool-reuse-policy | `fifo` | Pooled connection re-use policies
|feign.httpclient.hc5.pool-concurrency-policy | `strict` | Pool concurrency policies
|===
|===
@@ -393,7 +393,7 @@ favor for an opt-in approach.
[[spring-cloud-feign-hystrix-fallback]]
=== Feign Hystrix Fallbacks
Hystrix supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given `@FeignClient` set the `fallback` attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.
Hystrix supports the notion of a fallback: a default code path that is executed when the circuit is open or there is an error. To enable fallbacks for a given `@FeignClient` set the `fallback` attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.
[source,java,indent=0]
----
@@ -461,7 +461,7 @@ The circuit breaker name follows this pattern `<feignClientName>#<calledMethod>`
[[spring-cloud-feign-circuitbreaker-fallback]]
=== Feign Spring Cloud CircuitBreaker Fallbacks
Spring Cloud CircuitBreaker supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given `@FeignClient` set the `fallback` attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.
Spring Cloud CircuitBreaker supports the notion of a fallback: a default code path that is executed when the circuit is open or there is an error. To enable fallbacks for a given `@FeignClient` set the `fallback` attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.
[source,java,indent=0]
----
+4 -4
View File
@@ -4,14 +4,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-openfeign</artifactId>
<version>2.2.8.BUILD-SNAPSHOT</version>
<version>2.2.8.RELEASE</version>
<packaging>pom</packaging>
<name>Spring Cloud OpenFeign</name>
<description>Spring Cloud OpenFeign</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>2.3.2.RELEASE</version>
<version>2.3.4.RELEASE</version>
<relativePath/>
</parent>
<scm>
@@ -26,8 +26,8 @@
<properties>
<main.basedir>${basedir}</main.basedir>
<jackson.version>2.11.3</jackson.version>
<spring-cloud-commons.version>2.2.8.BUILD-SNAPSHOT</spring-cloud-commons.version>
<spring-cloud-netflix.version>2.2.8.BUILD-SNAPSHOT</spring-cloud-netflix.version>
<spring-cloud-commons.version>2.2.8.RELEASE</spring-cloud-commons.version>
<spring-cloud-netflix.version>2.2.8.RELEASE</spring-cloud-netflix.version>
<!-- Plugin versions -->
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign</artifactId>
<version>2.2.8.BUILD-SNAPSHOT</version>
<version>2.2.8.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-openfeign-core</artifactId>
@@ -16,6 +16,7 @@
package org.springframework.cloud.openfeign;
import feign.Feign;
import feign.hystrix.FallbackFactory;
import org.springframework.context.ApplicationContext;
@@ -28,6 +29,7 @@ import org.springframework.context.ApplicationContext;
*
* @author Sven Döring
* @author Matt King
* @author Sam Kruglov
*/
public class FeignClientBuilder {
@@ -69,6 +71,18 @@ public class FeignClientBuilder {
return this;
}
/**
* Applies a {@link FeignBuilderCustomizer} to the underlying
* {@link Feign.Builder}. May be called multiple times.
* @param customizer applied in the same order as supplied here after applying
* customizers found in the context.
* @return the {@link Builder} with the customizer added
*/
public Builder<T> customize(final FeignBuilderCustomizer customizer) {
this.feignClientFactoryBean.addCustomizer(customizer);
return this;
}
public Builder<T> contextId(final String contextId) {
this.feignClientFactoryBean.setContextId(contextId);
return this;
@@ -35,6 +35,8 @@ import feign.Target.HardCodedTarget;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.codec.ErrorDecoder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
@@ -62,6 +64,7 @@ import org.springframework.util.StringUtils;
* @author Olga Maciaszek-Sharma
* @author Ilia Ilinykh
* @author Marcin Grzejszczak
* @author Sam Kruglov
*/
public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
ApplicationContextAware, BeanFactoryAware {
@@ -71,6 +74,8 @@ public class FeignClientFactoryBean implements FactoryBean<Object>, Initializing
* lifecycle race condition.
***********************************/
private static Log LOG = LogFactory.getLog(FeignClientFactoryBean.class);
private Class<?> type;
private String name;
@@ -99,6 +104,8 @@ public class FeignClientFactoryBean implements FactoryBean<Object>, Initializing
private boolean followRedirects = new Request.Options().isFollowRedirects();
private List<FeignBuilderCustomizer> additionalCustomizers = new ArrayList<>();
@Override
public void afterPropertiesSet() {
Assert.hasText(contextId, "Context id must be set");
@@ -134,6 +141,7 @@ public class FeignClientFactoryBean implements FactoryBean<Object>, Initializing
.forEach(feignBuilderCustomizer -> feignBuilderCustomizer
.customize(builder));
}
additionalCustomizers.forEach(customizer -> customizer.customize(builder));
}
protected void configureFeign(FeignContext context, Feign.Builder builder) {
@@ -345,7 +353,7 @@ public class FeignClientFactoryBean implements FactoryBean<Object>, Initializing
}
throw new IllegalStateException(
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon or spring-cloud-starter-loadbalancer?");
}
@Override
@@ -365,6 +373,13 @@ public class FeignClientFactoryBean implements FactoryBean<Object>, Initializing
Feign.Builder builder = feign(context);
if (!StringUtils.hasText(url)) {
if (url != null && LOG.isWarnEnabled()) {
LOG.warn(
"The provided URL is empty. Will try picking an instance via load-balancing.");
}
else if (LOG.isDebugEnabled()) {
LOG.debug("URL not provided. Will use LoadBalancer.");
}
if (!name.startsWith("http")) {
url = "http://" + name;
}
@@ -483,6 +498,10 @@ public class FeignClientFactoryBean implements FactoryBean<Object>, Initializing
this.inheritParentContext = inheritParentContext;
}
public void addCustomizer(FeignBuilderCustomizer customizer) {
additionalCustomizers.add(customizer);
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
@@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Matt King
* @author Sam Kruglov
*/
public class FeignBuilderCustomizerTests {
@@ -78,6 +79,25 @@ public class FeignBuilderCustomizerTests {
context.close();
}
@Test
public void testBuildCustomizerOrderedWithAdditional() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
FeignBuilderCustomizerTests.SampleConfiguration3.class);
FeignClientFactoryBean clientFactoryBean = context
.getBean(FeignClientFactoryBean.class);
clientFactoryBean.addCustomizer(builder -> builder.logLevel(Logger.Level.BASIC));
clientFactoryBean.addCustomizer(Feign.Builder::doNotCloseAfterDecode);
FeignContext feignContext = context.getBean(FeignContext.class);
Feign.Builder builder = clientFactoryBean.feign(feignContext);
assertFeignBuilderField(builder, "logLevel", Logger.Level.BASIC);
assertFeignBuilderField(builder, "decode404", true);
assertFeignBuilderField(builder, "closeAfterDecode", false);
context.close();
}
private static FeignClientFactoryBean defaultFeignClientFactoryBean() {
FeignClientFactoryBean feignClientFactoryBean = new FeignClientFactoryBean();
feignClientFactoryBean.setContextId("test");
@@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import feign.Feign;
import feign.hystrix.FallbackFactory;
import org.hamcrest.Matchers;
import org.junit.Before;
@@ -40,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Sven Döring
* @author Sam Kruglov
*/
public class FeignClientBuilderTests {
@@ -58,6 +60,14 @@ public class FeignClientBuilderTests {
private static void assertFactoryBeanField(final FeignClientBuilder.Builder builder,
final String fieldName, final Object expectedValue) {
final Object value = getFactoryBeanField(builder, fieldName);
assertThat(value).as("Expected value for the field '" + fieldName + "':")
.isEqualTo(expectedValue);
}
@SuppressWarnings("unchecked")
private static <T> T getFactoryBeanField(final FeignClientBuilder.Builder builder,
final String fieldName) {
final Field factoryBeanField = ReflectionUtils
.findField(FeignClientBuilder.Builder.class, "feignClientFactoryBean");
ReflectionUtils.makeAccessible(factoryBeanField);
@@ -67,9 +77,7 @@ public class FeignClientBuilderTests {
final Field field = ReflectionUtils.findField(FeignClientFactoryBean.class,
fieldName);
ReflectionUtils.makeAccessible(field);
final Object value = ReflectionUtils.getField(field, factoryBean);
assertThat(value).as("Expected value for the field '" + fieldName + "':")
.isEqualTo(expectedValue);
return (T) ReflectionUtils.getField(field, factoryBean);
}
@Before
@@ -131,7 +139,8 @@ public class FeignClientBuilderTests {
.forType(TestFeignClient.class, "TestClient").inheritParentContext(false)
.fallback(TestFeignClientFallback.class)
.fallbackFactory(TestFeignClientFallbackFactory.class).decode404(true)
.url("Url/").path("/Path").contextId("TestContext");
.url("Url/").path("/Path").contextId("TestContext")
.customize(Feign.Builder::doNotCloseAfterDecode);
// then:
assertFactoryBeanField(builder, "applicationContext", this.applicationContext);
@@ -147,14 +156,21 @@ public class FeignClientBuilderTests {
assertFactoryBeanField(builder, "fallback", TestFeignClientFallback.class);
assertFactoryBeanField(builder, "fallbackFactory",
TestFeignClientFallbackFactory.class);
List<FeignBuilderCustomizer> additionalCustomizers = getFactoryBeanField(builder,
"additionalCustomizers");
assertThat(additionalCustomizers).hasSize(1);
}
@Test
public void forType_build() {
// given:
Mockito.when(this.applicationContext.getBean(FeignContext.class))
.thenThrow(new ClosedFileSystemException()); // throw an unusual exception
// in the
.thenThrow(new ClosedFileSystemException()); // throw
// an
// unusual
// exception
// in
// the
// FeignClientFactoryBean
final FeignClientBuilder.Builder builder = this.feignClientBuilder
.forType(TestClient.class, "TestClient");
+3 -3
View File
@@ -6,16 +6,16 @@
<parent>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>2.3.3.BUILD-SNAPSHOT</version>
<version>2.3.4.RELEASE</version>
<relativePath/>
</parent>
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
<version>2.2.8.BUILD-SNAPSHOT</version>
<version>2.2.8.RELEASE</version>
<packaging>pom</packaging>
<name>spring-cloud-openfeign-dependencies</name>
<description>Spring Cloud OpenFeign Dependencies</description>
<properties>
<feign.version>10.10.1</feign.version>
<feign.version>10.12</feign.version>
<feign-form.version>3.8.0</feign-form.version>
</properties>
<dependencyManagement>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign</artifactId>
<version>2.2.8.BUILD-SNAPSHOT</version>
<version>2.2.8.RELEASE</version>
<relativePath>..</relativePath>
</parent>
<artifactId>spring-cloud-starter-openfeign</artifactId>