我有一个Spring引导应用程序,它使用Feign通过Eureka调用外部Web服务。我希望能够使用 Feign 接口的模拟实现运行应用程序,这样我就可以在本地运行应用程序,而不必运行 Eureka 或外部 Web 服务。我曾设想定义一个允许我执行此操作的运行配置,但我正在努力使其工作。问题是,无论我尝试什么,Spring的"魔力"都在为Feign接口定义一个bean。
假装界面
@FeignClient(name = "http://foo-service")
public interface FooResource {
@RequestMapping(value = "/doSomething", method = GET)
String getResponse();
}
服务
public class MyService {
private FooResource fooResource;
...
public void getFoo() {
String response = this.fooResource.getResponse();
...
}
}
我尝试添加一个配置类,如果 Spring 配置文件是"本地",则有条件地注册一个 bean,但是当我使用该 Spring 配置文件运行应用程序时,从未调用过它:
@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";
}
};
}
}
在我的服务运行时,MyService
中的FooResource
成员变量的类型
HardCodedTarget(type=FoorResource, url=http://foo-service)
根据IntelliJ的说法。这是由Spring Cloud Netflix框架自动生成的类型,因此尝试与远程服务进行实际通信。
有没有办法根据配置设置有条件地覆盖 Feign 接口的实现?
解决方案如下所示:
public interface FeignBase {
@RequestMapping(value = "/get", method = RequestMethod.POST, headers = "Accept=application/json")
Result get(@RequestBody Token common);
}
然后定义基于 env 的接口:
@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
{}
最后,在您的服务 IMPL 中:
@Resource
private FeignBase feignBase;
在SpringCloud Netflix github存储库上发布了相同的问题后,一个有用的答案是使用Spring@Profile
注释。
我创建了一个没有用@EnabledFeignClients
注释的替代入口点类,并创建了一个新的配置类来定义我的Feign接口的实现。现在,这允许我在本地运行我的应用程序,而无需运行 Eureka 或任何依赖服务。
我正在使用一种更简单的解决方案来避免像 url 这样的变量参数有多个接口。
@FeignClient(name = "service.name", url = "${app.feign.clients.url}")
public interface YourClient{}
应用程序-{配置文件}.属性
app.feign.clients.url=http://localhost:9999