Commit d78da7b9 by Erik Kringen Committed by Spencer Gibb

Add support for Feign.SetterFactory (#1673)

Fixes gh-1414
parent c795bd16
......@@ -976,6 +976,7 @@ Spring Cloud Netflix _does not_ provide the following beans by default for feign
* `ErrorDecoder`
* `Request.Options`
* `Collection<RequestInterceptor>`
* `SetterFactory`
Creating a bean of one of those type and placing it in a `@FeignClient` configuration (such as `FooConfiguration` above) allows you to override each one of the beans described. Example:
......
......@@ -17,14 +17,17 @@
package org.springframework.cloud.netflix.feign;
import org.springframework.util.Assert;
import feign.Feign;
import feign.Target;
import feign.hystrix.FallbackFactory;
import feign.hystrix.HystrixFeign;
import org.springframework.util.Assert;
import feign.hystrix.SetterFactory;
/**
* @author Spencer Gibb
* @author Erik Kringen
*/
@SuppressWarnings("unchecked")
class HystrixTargeter implements Targeter {
......@@ -36,6 +39,11 @@ class HystrixTargeter implements Targeter {
return feign.target(target);
}
feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
SetterFactory setterFactory = getOptional(factory.getName(), context,
SetterFactory.class);
if (setterFactory != null) {
builder.setterFactory(setterFactory);
}
Class<?> fallback = factory.getFallback();
if (fallback != void.class) {
return targetWithFallback(factory.getName(), context, target, builder, fallback);
......@@ -95,4 +103,9 @@ class HystrixTargeter implements Targeter {
}
return (T) fallbackInstance;
}
private <T> T getOptional(String feignClientName, FeignContext context,
Class<T> beanType) {
return context.getInstance(feignClientName, beanType);
}
}
......@@ -25,6 +25,7 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.ParseException;
import java.util.ArrayList;
......@@ -68,14 +69,19 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import feign.Client;
import feign.Feign;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.Target;
import feign.hystrix.FallbackFactory;
import feign.hystrix.SetterFactory;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
......@@ -85,6 +91,7 @@ import rx.Single;
/**
* @author Spencer Gibb
* @author Jakub Narloch
* @author Erik Kringen
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = FeignClientTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
......@@ -124,6 +131,9 @@ public class FeignClientTests {
@Qualifier("localapp3FeignClient")
HystrixClient namedHystrixClient;
@Autowired
HystrixSetterFactoryClient hystrixSetterFactoryClient;
protected enum Arg {
A, B;
......@@ -298,18 +308,47 @@ public class FeignClientTests {
}
}
@FeignClient(name = "localapp5", configuration = TestHystrixSetterFactoryClientConfig.class)
protected interface HystrixSetterFactoryClient {
@RequestMapping(method = RequestMethod.GET, path = "/hellos")
HystrixCommand<List<Hello>> getHellosHystrix();
}
public static class TestHystrixSetterFactoryClientConfig {
public static final String SETTER_PREFIX = "SETTER-";
@Bean
public SetterFactory commandKeyIsRequestLineSetterFactory() {
return new SetterFactory() {
@Override public HystrixCommand.Setter create(Target<?> target,
Method method) {
String groupKey = SETTER_PREFIX + target.name();
RequestMapping requestMapping = method
.getAnnotation(RequestMapping.class);
String commandKey =
SETTER_PREFIX + requestMapping.method()[0] + " " + requestMapping
.path()[0];
return HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
}
};
}
}
@Configuration
@EnableAutoConfiguration
@RestController
@EnableFeignClients(clients = { TestClientServiceId.class, TestClient.class,
DecodingTestClient.class, HystrixClient.class, HystrixClientWithFallBackFactory.class },
defaultConfiguration = TestDefaultFeignConfig.class)
DecodingTestClient.class, HystrixClient.class, HystrixClientWithFallBackFactory.class,
HystrixSetterFactoryClient.class},
defaultConfiguration = TestDefaultFeignConfig.class)
@RibbonClients({
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp1", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp2", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp3", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp4", configuration = LocalRibbonClientConfiguration.class)
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp1", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp2", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp3", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp4", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp5", configuration = LocalRibbonClientConfiguration.class)
})
protected static class Application {
......@@ -525,12 +564,16 @@ public class FeignClientTests {
}
@Test
public void testHystrixCommand() {
public void testHystrixCommand() throws NoSuchMethodException {
HystrixCommand<List<Hello>> command = this.testClient.getHellosHystrix();
assertNotNull("command was null", command);
assertEquals(
"Hystrix command group name should match the name of the feign client",
"localapp", command.getCommandGroup().name());
"Hystrix command group name should match the name of the feign client",
"localapp", command.getCommandGroup().name());
String configKey = Feign.configKey(TestClient.class,
TestClient.class.getMethod("getHellosHystrix", (Class<?>[]) null));
assertEquals("Hystrix command key name should match the feign config key",
configKey, command.getCommandKey().name());
List<Hello> hellos = command.execute();
assertNotNull("hellos was null", hellos);
assertEquals("hellos didn't match", hellos, getHelloList());
......@@ -658,6 +701,25 @@ public class FeignClientTests {
assertNotNull("namedHystrixClient was null", this.namedHystrixClient);
}
@Test
public void testHystrixSetterFactory() {
HystrixCommand<List<Hello>> command = this.hystrixSetterFactoryClient
.getHellosHystrix();
assertNotNull("command was null", command);
String setterPrefix = TestHystrixSetterFactoryClientConfig.SETTER_PREFIX;
assertEquals(
"Hystrix command group name should match the name of the feign client with a prefix of "
+ setterPrefix, setterPrefix + "localapp5",
command.getCommandGroup().name());
assertEquals(
"Hystrix command key name should match the request method (space) request path with a prefix of "
+ setterPrefix, setterPrefix + "GET /hellos",
command.getCommandKey().name());
List<Hello> hellos = command.execute();
assertNotNull("hellos was null", hellos);
assertEquals("hellos didn't match", hellos, getHelloList());
}
@Data
@AllArgsConstructor
@NoArgsConstructor
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment