我试图使用Feign客户端。以下是我的feing客户:
import com.eprogrammerz.examples.domain.Movie;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Created by Yogen on 12/26/2016.
*/
@FeignClient(name = "movie-api")
public interface MovieApi {
@RequestMapping(method = RequestMethod.GET, value = "/movies/{id}")
Movie getMovie(@PathVariable("id") Long id);
}
我从简单的服务中调用它,如下所示:
@Service
public class MovieService {
@Autowired
MovieApi movieApi;
public Movie findMovie(Long id){
Movie movieOfTheDay = movieApi.getMovie(id);
return movieOfTheDay;
}
}
我的春季启动应用程序如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@EnableFeignClients(basePackages = {"com.eprogrammerz.examples"})
@EnableCircuitBreaker
@SpringBootApplication
public class ClientAppApplication {
public static void main(String[] args) {
SpringApplication.run(ClientAppApplication.class, args);
}
}
的build.gradle
buildscript {
ext {
springBootVersion = '1.4.3.RELEASE'
}
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
jar {
baseName = 'client-app'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
jcenter()
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
compile('org.springframework.cloud:spring-cloud-starter-feign')
// https://mvnrepository.com/artifact/com.netflix.hystrix/hystrix-core
compile('org.springframework.cloud:spring-cloud-starter-hystrix')
compile("org.springframework.boot:spring-boot-starter-web"){
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Camden.BUILD-SNAPSHOT"
mavenBom "org.springframework.boot:spring-boot-starter-parent:${springBootVersion}"
}
}
我收到如下错误:
2016-12-30 13:07:16.894 INFO 6748 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 39 ms
2016-12-30 13:07:16.939 INFO 6748 --- [nio-8082-exec-1] c.e.e.controllers.RequestController : Calling findMovie(1203)
2016-12-30 13:07:17.240 INFO 6748 --- [rix-movie-api-1] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@547496c2: startup date [Fri Dec 30 13:07:17 EST 2016]; parent: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@542e560f
2016-12-30 13:07:17.318 INFO 6748 --- [rix-movie-api-1] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2016-12-30 13:07:17.619 INFO 6748 --- [rix-movie-api-1] c.netflix.config.ChainedDynamicProperty : Flipping property: movie-api.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2016-12-30 13:07:17.670 INFO 6748 --- [rix-movie-api-1] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-movie-api
2016-12-30 13:07:17.727 INFO 6748 --- [rix-movie-api-1] c.netflix.loadbalancer.BaseLoadBalancer : Client:movie-api instantiated a LoadBalancer:DynamicServerListLoadBalancer:{NFLoadBalancer:name=movie-api,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2016-12-30 13:07:17.739 INFO 6748 --- [rix-movie-api-1] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater
2016-12-30 13:07:17.746 INFO 6748 --- [rix-movie-api-1] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client movie-api initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=movie-api,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:com.netflix.loadbalancer.ConfigurationBasedServerList@45bcfd5
2016-12-30 13:07:18.191 ERROR 6748 --- [nio-8082-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.netflix.hystrix.exception.HystrixRuntimeException: MovieApi#getMovie(Long) failed and no fallback available.] with root cause
com.netflix.client.ClientException: Load balancer does not have available server for client: movie-api
at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:468) ~[ribbon-loadbalancer-2.2.0.jar:2.2.0]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184) ~[ribbon-loadbalancer-2.2.0.jar:2.2.0]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.2.0.jar:2.2.0]
at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Subscriber.setProducer(Subscriber.java:209) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Observable.subscribe(Observable.java:10307) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Observable.subscribe(Observable.java:10274) ~[rxjava-1.1.10.jar:1.1.10]
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:445) ~[rxjava-1.1.10.jar:1.1.10]
at rx.observables.BlockingObservable.single(BlockingObservable.java:342) ~[rxjava-1.1.10.jar:1.1.10]
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:102) ~[ribbon-loadbalancer-2.2.0.jar:2.2.0]
at org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:63) ~[spring-cloud-netflix-core-1.2.4.BUILD-SNAPSHOT.jar:1.2.4.BUILD-SNAPSHOT]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97) ~[feign-core-9.3.1.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) ~[feign-core-9.3.1.jar:na]
at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:108) ~[feign-hystrix-9.3.1.jar:na]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:301) ~[hystrix-core-1.5.6.jar:1.5.6]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:297) ~[hystrix-core-1.5.6.jar:1.5.6]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94) ~[rxjava-1.1.10.jar:1.1.10]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:56) ~[hystrix-core-1.5.6.jar:1.5.6]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:47) ~[hystrix-core-1.5.6.jar:1.5.6]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction.call(HystrixContexSchedulerAction.java:69) ~[hystrix-core-1.5.6.jar:1.5.6]
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) ~[rxjava-1.1.10.jar:1.1.10]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_51]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_51]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_51]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_51]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_51]
我尝试了不同的方式。但无法找出解决方案。我也无法在Spring Cloud Netflix找到有关此内容的任何信息。我也无法在discussion thread on StackOverflow找到任何信息。
我在这里失踪了什么? TIA。
进一步详情:
用于movie-api微服务的application.yml如下:
server:
port: 8090
logging:
config: classpath:log4j2.yml
spring:
application:
name: movie-api
movie-api模块上的Spring启动应用程序:
@SpringBootApplication
public class MovieApiApplication {
public static void main(String[] args) {
SpringApplication.run(MovieApiApplication.class, args);
}
}
控制器如下:
@RestController
@Slf4j
public class MovieController {
@Autowired
private MovieRepository movieRepository;
@RequestMapping("/movies/{id}")
public ResponseEntity<Movie> getBook(@PathVariable("id") Long id){
log.trace("getBook({})",id);
Optional<Movie> movie = Optional.of(movieRepository.findOneById(id));
if(movie.isPresent())
return new ResponseEntity(movie.get(), HttpStatus.OK);
return new ResponseEntity<Movie>(HttpStatus.NOT_FOUND);
}
}
答案 0 :(得分:20)
经过研究,并在@Bloodysock的帮助下,我发现我在“客户端 - 应用程序”中缺少远程服务器的注册。微服务。该文件位于Spring Cloud Netflix。
我在application.yml
client-app
&#39; movie-api:
ribbon:
listOfServers: http://localhost:8090
&#39;中使用了没有Eureka的功能区。微服务:
$.post("https://login.salesforce.com/services/oauth2/token",
{
grant_type:"password",
dataType : 'jsonp',
headers : {Accept : "application/json","Access-Control-Allow-Origin" : "*"},
client_id:"CLIENTID",
client_secret:"CLIENTSECRET",
username: "uname",
password: "password"
},
function(data,status){
//my_function(data);
console.log(data);
});
function my_function(data){
alert(data);
}
答案 1 :(得分:7)
问题是您的服务并不知道所请求服务的主机。如果您使用的是Eureka,请将此行放在.properties或.yml文件中:
eureka.client.fetchRegistry =真
OR
尤里卡: 客户: fetchRegistry:true
它将使您的服务与Eureka交谈,并发现所请求服务的主机。
答案 2 :(得分:1)
如果Spring Cloud设置不支持在application.properties /application.yml中指定服务器,则必须在Configuration类中配置服务URL。
请注意我的application.properties中的 警告消息 [Spring Boot v2.0.0RELEASE,spring-cloud-starter-feign&amp; spring-cloud-starter-ribbon v 1.4.3.RELEASE]
所以我做的是编写一个Configuration类,如下所示:
@Configuration
class LocalRibbonClientConfiguration {
@Bean
public ServerList<Server> ribbonServerList() {
// return new ConfigurationBasedServerList();
StaticServerList<Server> staticServerList = new StaticServerList<>((new Server("localhost", 8001)),
new Server("localhost", 8000));
return staticServerList;
}
}
然后,配置Spring Boot Application以使用此配置,如下所示:
@SpringBootApplication
@EnableFeignClients("my-package.currencyconversionservice")
@RibbonClient(name = "currency-conversion-service", configuration = LocalRibbonClientConfiguration.class)
public class CurrencyConversionServiceApplication {
// nothing new here...
}
无需更改Feign Proxy类。仅发布此帖子作为问题的完整解决方案:
@FeignClient(name="currency-exchange-service")
@RibbonClient(name="currency-exchange-service")
public interface CurrencyExchangeServiceProxy {
@GetMapping("/currency-exchange/from/{from}/to/{to}")
public CurrencyConversionBean retrieveExchangeValue(@PathVariable("from") String from, @PathVariable("to") String to);
}
这就是全部。问题得到解决。
答案 3 :(得分:1)
我几乎浪费了2个小时来寻找根本原因。我在客户端应用程序中错误地导入了EnableEurekaClient,这是问题的根本原因。我终于通过删除导入解决了这个问题。令我惊讶的是,@ EnableDiscoveryClient不需要以下依赖项。 但是,如果您使用的是Eureka命名服务器,则必须使用该服务器。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
答案 4 :(得分:0)
确保您的ribbion客户是正确的。
package com.in28minutes.microservices.currencyconversionservice;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name="currency-exchange-service")
@RibbonClient(name="currency-exchange-service")
public interface CurrencyExchangeServiceProxy {
@GetMapping("/currency-exchange/from/{from}/to/{to}")
public CurrencyConversionBean retrieveExchangeValue
(@PathVariable("from") String from, @PathVariable("to") String to); //mention correct pathvariables
}
答案 5 :(得分:0)
问题是您的服务不知道所请求服务的主机。如果您使用的是Eureka和zuul,请将此行放在zuul .properties或.yml文件中:
eureka.client.fetch-registry = true
答案 6 :(得分:0)
似乎ClientAppApplication
不知道您的eureka服务器的地址。
您可以检查一下applation.yml
eureka
instance:
hostname: cloud-feignorder-consume
client:
register-with-eureka: false #default true
fetch-registry: true #default true
最后一行应该检查属性'eureka.client.fetch-registry'。它应该为true或不为sign。然后您的客户端可以从eureka服务器获取服务器列表。
答案 7 :(得分:0)
如果没有eureka,则在客户端应用程序中,如果没有application.yml而不是application.properties文件,则可以在客户端应用程序重新启动之前按如下所示设置属性:
currency-exchange-service.ribbon.listOfServers:http:// localhost:8000,http:// localhost:8001
答案 8 :(得分:-1)
您需要将Ribbon和Eureka Client一起添加,否则将不会获取该服务。
在我的pom.xml中,我拥有:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
在我的服务代理中:
@FeignClient(name = "movie-api")
@RibbonClient(name = "movie-api")
public interface MovieApi {
@RequestMapping(method = RequestMethod.GET, value = "/movies/{id}")
Movie getMovie(@PathVariable("id") Long id);
}