6
votes

I have a Spring boot application which uses Feign to call an external web service via Eureka. I'd like to be able to run the application using a mocked out implementation of the Feign interface, so I can run the application locally without necessarily having Eureka or the external web service running. I had imagined defining a run configuration that allowed me to do this, but am struggling to get this working. The issue is that the Spring "magic" is defining a bean for the Feign interface no matter what I try.

Feign interface

@FeignClient(name = "http://foo-service")
public interface FooResource {
    @RequestMapping(value = "/doSomething", method = GET)
    String getResponse();
}

Service

public class MyService {
    private FooResource fooResource;

    ...

    public void getFoo() {
        String response = this.fooResource.getResponse();
        ...
    }
}

I tried adding a configuration class that conditionally registered a bean if the Spring profile was "local", but that was never called when I ran the application with that Spring profile:

@Configuration
public class AppConfig {
    @Bean
    @ConditionalOnProperty(prefix = "spring.profile", name = "active", havingValue="local")
    public FooResource fooResource() {
        return new FooResource() {
            @Override
            public String getResponse() {
                return "testing";
            }
        };
    }
}

At the point my service runs, the FooResource member variable in MyService is of type

HardCodedTarget(type=FoorResource, url=http://foo-service)

according to IntelliJ. This is the type that is automatically generated by the Spring Cloud Netflix framework, and so tries to actually communicate with the remote service.

Is there a way I can conditionally override the implementation of the Feign interface depending on a configuration setting?

3

3 Answers

5
votes

the solution is like below:

public interface FeignBase {
   @RequestMapping(value = "/get", method = RequestMethod.POST, headers = "Accept=application/json")
   Result get(@RequestBody Token common);
}

then define your env based interface:

@Profile("prod")
@FeignClient(name = "service.name")
public interface Feign1 extends FeignBase 
{}

@Profile("!prod")
@FeignClient(name = "service.name", url = "your url")
public interface Feign2 extends FeignBase 
{}

finally, in your service impl:

@Resource
private FeignBase feignBase;
4
votes

Having posted the same question on the Spring Cloud Netflix github repository, a useful answer was to use the Spring @Profile annotation.

I created an alternative entry point class that was not annotated with @EnabledFeignClients, and created a new configuration class that defined implementations for my Feign interfaces. This now allows me to run my application locally without the need to have Eureka running, or any dependent services.

1
votes

I'm using a simpler solution to avoid having multiples interfaces for a variable parameter like url.

    @FeignClient(name = "service.name", url = "${app.feign.clients.url}")
    public interface YourClient{}

application-{profile}.properties

app.feign.clients.url=http://localhost:9999