Browse Source
* add feign client properties * configure feign builder from properties if exists * change string config to class config and add unit test for feign client using configuration properties * refactoring and add primary flag configuration * add decode404 in feign client configuration properties * change unit test properties decode404 to true * remove lombok from FeignClientProperties and change primary attribute to default-to-properties fixes gh-1931pull/6/head
6 changed files with 468 additions and 4 deletions
@ -0,0 +1,174 @@
@@ -0,0 +1,174 @@
|
||||
/* |
||||
* Copyright 2013-2017 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 |
||||
* |
||||
* http://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.netflix.feign; |
||||
|
||||
import feign.Logger; |
||||
import feign.RequestInterceptor; |
||||
import feign.Retryer; |
||||
import feign.codec.ErrorDecoder; |
||||
import lombok.Data; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Objects; |
||||
|
||||
/** |
||||
* @author Eko Kurniawan Khannedy |
||||
*/ |
||||
@ConfigurationProperties("feign.client") |
||||
public class FeignClientProperties { |
||||
|
||||
private boolean defaultToProperties = true; |
||||
|
||||
private String defaultConfig = "default"; |
||||
|
||||
private Map<String, FeignClientConfiguration> config = new HashMap<>(); |
||||
|
||||
public boolean isDefaultToProperties() { |
||||
return defaultToProperties; |
||||
} |
||||
|
||||
public void setDefaultToProperties(boolean defaultToProperties) { |
||||
this.defaultToProperties = defaultToProperties; |
||||
} |
||||
|
||||
public String getDefaultConfig() { |
||||
return defaultConfig; |
||||
} |
||||
|
||||
public void setDefaultConfig(String defaultConfig) { |
||||
this.defaultConfig = defaultConfig; |
||||
} |
||||
|
||||
public Map<String, FeignClientConfiguration> getConfig() { |
||||
return config; |
||||
} |
||||
|
||||
public void setConfig(Map<String, FeignClientConfiguration> config) { |
||||
this.config = config; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (o == null || getClass() != o.getClass()) return false; |
||||
FeignClientProperties that = (FeignClientProperties) o; |
||||
return defaultToProperties == that.defaultToProperties && |
||||
Objects.equals(defaultConfig, that.defaultConfig) && |
||||
Objects.equals(config, that.config); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return Objects.hash(defaultToProperties, defaultConfig, config); |
||||
} |
||||
|
||||
public static class FeignClientConfiguration { |
||||
|
||||
private Logger.Level loggerLevel; |
||||
|
||||
private Integer connectTimeout; |
||||
|
||||
private Integer readTimeout; |
||||
|
||||
private Class<Retryer> retryer; |
||||
|
||||
private Class<ErrorDecoder> errorDecoder; |
||||
|
||||
private List<Class<RequestInterceptor>> requestInterceptors; |
||||
|
||||
private Boolean decode404; |
||||
|
||||
public Logger.Level getLoggerLevel() { |
||||
return loggerLevel; |
||||
} |
||||
|
||||
public void setLoggerLevel(Logger.Level loggerLevel) { |
||||
this.loggerLevel = loggerLevel; |
||||
} |
||||
|
||||
public Integer getConnectTimeout() { |
||||
return connectTimeout; |
||||
} |
||||
|
||||
public void setConnectTimeout(Integer connectTimeout) { |
||||
this.connectTimeout = connectTimeout; |
||||
} |
||||
|
||||
public Integer getReadTimeout() { |
||||
return readTimeout; |
||||
} |
||||
|
||||
public void setReadTimeout(Integer readTimeout) { |
||||
this.readTimeout = readTimeout; |
||||
} |
||||
|
||||
public Class<Retryer> getRetryer() { |
||||
return retryer; |
||||
} |
||||
|
||||
public void setRetryer(Class<Retryer> retryer) { |
||||
this.retryer = retryer; |
||||
} |
||||
|
||||
public Class<ErrorDecoder> getErrorDecoder() { |
||||
return errorDecoder; |
||||
} |
||||
|
||||
public void setErrorDecoder(Class<ErrorDecoder> errorDecoder) { |
||||
this.errorDecoder = errorDecoder; |
||||
} |
||||
|
||||
public List<Class<RequestInterceptor>> getRequestInterceptors() { |
||||
return requestInterceptors; |
||||
} |
||||
|
||||
public void setRequestInterceptors(List<Class<RequestInterceptor>> requestInterceptors) { |
||||
this.requestInterceptors = requestInterceptors; |
||||
} |
||||
|
||||
public Boolean getDecode404() { |
||||
return decode404; |
||||
} |
||||
|
||||
public void setDecode404(Boolean decode404) { |
||||
this.decode404 = decode404; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (o == null || getClass() != o.getClass()) return false; |
||||
FeignClientConfiguration that = (FeignClientConfiguration) o; |
||||
return loggerLevel == that.loggerLevel && |
||||
Objects.equals(connectTimeout, that.connectTimeout) && |
||||
Objects.equals(readTimeout, that.readTimeout) && |
||||
Objects.equals(retryer, that.retryer) && |
||||
Objects.equals(errorDecoder, that.errorDecoder) && |
||||
Objects.equals(requestInterceptors, that.requestInterceptors) && |
||||
Objects.equals(decode404, that.decode404); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return Objects.hash(loggerLevel, connectTimeout, readTimeout, retryer, |
||||
errorDecoder, requestInterceptors, decode404); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,163 @@
@@ -0,0 +1,163 @@
|
||||
/* |
||||
* Copyright 2013-2015 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 |
||||
* |
||||
* http://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.netflix.feign; |
||||
|
||||
import feign.RequestInterceptor; |
||||
import feign.RequestTemplate; |
||||
import feign.RetryableException; |
||||
import feign.Retryer; |
||||
import feign.codec.ErrorDecoder; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.test.annotation.DirtiesContext; |
||||
import org.springframework.test.context.TestPropertySource; |
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RequestMethod; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* @author Eko Kurniawan Khannedy |
||||
*/ |
||||
@RunWith(SpringJUnit4ClassRunner.class) |
||||
@SpringBootTest(classes = FeignClientUsingPropertiesTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT) |
||||
@TestPropertySource("classpath:feign-properties.properties") |
||||
@DirtiesContext |
||||
public class FeignClientUsingPropertiesTests { |
||||
|
||||
@Autowired |
||||
FeignContext context; |
||||
|
||||
@Autowired |
||||
private ApplicationContext applicationContext; |
||||
|
||||
@Value("${local.server.port}") |
||||
private int port = 0; |
||||
|
||||
private FeignClientFactoryBean fooFactoryBean; |
||||
|
||||
private FeignClientFactoryBean barFactoryBean; |
||||
|
||||
public FeignClientUsingPropertiesTests() { |
||||
fooFactoryBean = new FeignClientFactoryBean(); |
||||
fooFactoryBean.setName("foo"); |
||||
fooFactoryBean.setType(FeignClientFactoryBean.class); |
||||
|
||||
barFactoryBean = new FeignClientFactoryBean(); |
||||
barFactoryBean.setName("bar"); |
||||
barFactoryBean.setType(FeignClientFactoryBean.class); |
||||
} |
||||
|
||||
public FooClient fooClient() { |
||||
fooFactoryBean.setApplicationContext(applicationContext); |
||||
return fooFactoryBean.feign(context).target(FooClient.class, "http://localhost:" + this.port); |
||||
} |
||||
|
||||
public BarClient barClient() { |
||||
barFactoryBean.setApplicationContext(applicationContext); |
||||
return barFactoryBean.feign(context).target(BarClient.class, "http://localhost:" + this.port); |
||||
} |
||||
|
||||
@Test |
||||
public void testFoo() { |
||||
String response = fooClient().foo(); |
||||
assertNotNull("OK", response); |
||||
} |
||||
|
||||
@Test(expected = RetryableException.class) |
||||
public void testBar() { |
||||
barClient().bar(); |
||||
fail("it should timeout"); |
||||
} |
||||
|
||||
protected interface FooClient { |
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/foo") |
||||
String foo(); |
||||
} |
||||
|
||||
protected interface BarClient { |
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/bar") |
||||
String bar(); |
||||
} |
||||
|
||||
@Configuration |
||||
@EnableAutoConfiguration |
||||
@RestController |
||||
protected static class Application { |
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/foo") |
||||
public String foo(HttpServletRequest request) throws IllegalAccessException { |
||||
if ("Foo".equals(request.getHeader("Foo")) && |
||||
"Bar".equals(request.getHeader("Bar"))) { |
||||
return "OK"; |
||||
} else { |
||||
throw new IllegalAccessException("It should has Foo and Bar header"); |
||||
} |
||||
} |
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/bar") |
||||
public String bar() throws InterruptedException { |
||||
Thread.sleep(2000L); |
||||
return "OK"; |
||||
} |
||||
|
||||
} |
||||
|
||||
public static class FooRequestInterceptor implements RequestInterceptor { |
||||
@Override |
||||
public void apply(RequestTemplate template) { |
||||
template.header("Foo", "Foo"); |
||||
} |
||||
} |
||||
|
||||
public static class BarRequestInterceptor implements RequestInterceptor { |
||||
@Override |
||||
public void apply(RequestTemplate template) { |
||||
template.header("Bar", "Bar"); |
||||
} |
||||
} |
||||
|
||||
public static class NoRetryer implements Retryer { |
||||
|
||||
@Override |
||||
public void continueOrPropagate(RetryableException e) { |
||||
throw e; |
||||
} |
||||
|
||||
@Override |
||||
public Retryer clone() { |
||||
return this; |
||||
} |
||||
} |
||||
|
||||
public static class DefaultErrorDecoder extends ErrorDecoder.Default { |
||||
} |
||||
|
||||
} |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
# This configuration used by test class org.springframework.cloud.netflix.feign.FeignClientUsingPropertiesTests |
||||
|
||||
logging.level.org.springframework.cloud.netflix.feign=debug |
||||
|
||||
feign.client.default-to-properties=true |
||||
feign.client.default-config=default |
||||
|
||||
feign.client.config.default.connectTimeout=5000 |
||||
feign.client.config.default.readTimeout=5000 |
||||
feign.client.config.default.loggerLevel=full |
||||
feign.client.config.default.errorDecoder=org.springframework.cloud.netflix.feign.FeignClientUsingPropertiesTests.DefaultErrorDecoder |
||||
feign.client.config.default.retryer=org.springframework.cloud.netflix.feign.FeignClientUsingPropertiesTests.NoRetryer |
||||
feign.client.config.default.decode404=true |
||||
|
||||
feign.client.config.foo.requestInterceptors[0]=org.springframework.cloud.netflix.feign.FeignClientUsingPropertiesTests.FooRequestInterceptor |
||||
feign.client.config.foo.requestInterceptors[1]=org.springframework.cloud.netflix.feign.FeignClientUsingPropertiesTests.BarRequestInterceptor |
||||
|
||||
feign.client.config.bar.connectTimeout=1000 |
||||
feign.client.config.bar.readTimeout=1000 |
Loading…
Reference in new issue