Merge pull request #655 from Oreste-Luci/master
* pull655: Add support for placeholders in @FeignClient definitions
This commit is contained in:
@@ -790,6 +790,16 @@ NOTE: The `serviceId` attribute is now deprecated in favor of the `name` attribu
|
||||
|
||||
WARNING: Previously, using the `url` attribute, did not require the `name` attribute. Using `name` is now required.
|
||||
|
||||
Placeholders are supported in the `name` and `url` attributes.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@FeignClient(name = "${feign.name}", url = "${feign.url}")
|
||||
public interface StoreClient {
|
||||
//..
|
||||
}
|
||||
----
|
||||
|
||||
Spring Cloud Netflix provides the following beans by default for feign (`BeanType` beanName: `ClassName`):
|
||||
|
||||
* `Decoder` feignDecoder: `ResponseEntityDecoder` (which wraps a `SpringDecoder`)
|
||||
|
||||
@@ -39,14 +39,16 @@ public @interface FeignClient {
|
||||
|
||||
/**
|
||||
* The serviceId with optional protocol prefix. Synonym for {@link #serviceId()
|
||||
* serviceId}. Either serviceId or url must be specified but not both.
|
||||
* serviceId}. Either serviceId or url must be specified but not both. Can be
|
||||
* specified as property key, eg: ${propertyKey}.
|
||||
*/
|
||||
@AliasFor("name")
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* The serviceId with optional protocol prefix. Synonym for {@link #value() value}.
|
||||
* Either serviceId or url must be specified but not both.
|
||||
* Either serviceId or url must be specified but not both. Can be
|
||||
* specified as property key, eg: ${propertyKey}.
|
||||
*
|
||||
* @deprecated use {@link #name() name} instead
|
||||
*/
|
||||
|
||||
@@ -18,8 +18,10 @@ package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -34,6 +36,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
@@ -186,9 +189,11 @@ public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
if (!StringUtils.hasText(name)) {
|
||||
name = (String) attributes.get("value");
|
||||
}
|
||||
name = resolve(name);
|
||||
if (!StringUtils.hasText(name)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String host = null;
|
||||
try {
|
||||
host = new URI("http://" + name).getHost();
|
||||
@@ -199,8 +204,25 @@ public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
return name;
|
||||
}
|
||||
|
||||
private String resolve(String value) {
|
||||
if (StringUtils.hasText(value )
|
||||
&& this.resourceLoader instanceof ConfigurableApplicationContext) {
|
||||
return ((ConfigurableApplicationContext)this.resourceLoader)
|
||||
.getEnvironment().resolvePlaceholders(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String getUrl(Map<String, Object> attributes) {
|
||||
return (String) attributes.get("url");
|
||||
String url = resolve((String) attributes.get("url"));
|
||||
if (StringUtils.hasText(url)) {
|
||||
try {
|
||||
new URL(url);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IllegalArgumentException(url + " is malformed", e);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
protected ClassPathScanningCandidateComponentProvider getScanner() {
|
||||
|
||||
@@ -57,6 +57,28 @@ public class FeignClientValidationTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validPlaceholder() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
PlaceholderUrlConfiguration.class);
|
||||
assertNotNull(context.getBean(PlaceholderUrlConfiguration.Client.class));
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(FeignAutoConfiguration.class)
|
||||
@EnableFeignClients(clients = PlaceholderUrlConfiguration.Client.class)
|
||||
protected static class PlaceholderUrlConfiguration {
|
||||
|
||||
@FeignClient(name="example", url="${feignClient.url:http://example.com}")
|
||||
interface Client {
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/")
|
||||
@Deprecated
|
||||
String get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validLoadBalanced() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
|
||||
@@ -60,6 +60,9 @@ public class FeignClientScanningTests {
|
||||
@Autowired
|
||||
private TestClient testClient;
|
||||
|
||||
@Autowired
|
||||
private TestClientByKey testClientByKey;
|
||||
|
||||
@Autowired
|
||||
private Client feignClient;
|
||||
|
||||
@@ -69,6 +72,12 @@ public class FeignClientScanningTests {
|
||||
String getHello();
|
||||
}
|
||||
|
||||
@FeignClient("${feignClient.localappName}")
|
||||
protected interface TestClientByKey {
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
||||
String getHello();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
@@ -94,6 +103,13 @@ public class FeignClientScanningTests {
|
||||
assertEquals("first hello didn't match", "hello world 1", hello);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleTypeByKey() {
|
||||
String hello = this.testClientByKey.getHello();
|
||||
assertNotNull("hello was null", hello);
|
||||
assertEquals("first hello didn't match", "hello world 1", hello);
|
||||
}
|
||||
|
||||
// Load balancer with fixed server list for "local" pointing to localhost
|
||||
@Configuration
|
||||
public static class LocalRibbonClientConfiguration {
|
||||
|
||||
@@ -37,3 +37,5 @@ zuul:
|
||||
stores:
|
||||
url: http://localhost:8081
|
||||
path: /stores/**
|
||||
feignClient:
|
||||
localappName: localapp
|
||||
Reference in New Issue
Block a user