先貼代碼:
@RestController public class CallHelloController { @Autowired private LoadBalancerClient loadBalancerClient; @Autowired private RestTemplate restTemplate;
@RequestMapping("/call") public String call(){ ServiceInstance serviceInstance = loadBalancerClient.choose("service-producer"); System.out.println("服務地址:" + serviceInstance.getUri()); System.out.println("服務名稱:" + serviceInstance.getServiceId()); String callServiceResult = restTemplate.getForObject(serviceInstance.getUri().toString() + "/hello", String.class); System.out.println(callServiceResult); return callServiceResult; }
@SpringBootApplication @EnableDiscoveryClient //單純的消費(不對外提供服務)可以不注冊 @RibbonClient(name = "service-producer", configuration = RibbonConfig.class) @ComponentScan(excludeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION, value=ExcludeFromComponentScan.class)} ) public class SpringCloudConsulConsumerApplication { public static void main(String[] args) { SpringApplication.run(SpringCloudConsulConsumerApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
application.properties
spring.application.name=spring-cloud-consul-producer server.port=8802 spring.cloud.consul.host=localhost spring.cloud.consul.port=8500 #注冊到consul的服務名稱 spring.cloud.consul.discovery.serviceName=service-producer
實際上,/call請求映射方法存在問題;
問題是 因為 LoadBalancedClient 這里的 choose 根據 Consul注冊的服務名(spring.cloud.consul.discovery.serviceName=service-producer) 命中一個服務提供者;
這里就不能使用加了LoadBalanced注解的RestTemplate對象了,因為會根據 host 去Consul查找服務提供者,這樣就會拋異常 :No instances available for XXX ,也就是找不到指定的服務ID
原因:"服務地址:" + serviceInstance.getUri()這兒出現了問題。
即:
LoadBalancerClient進行手動的http請求;Ribbon集成了Apache HttpClient 、 OkHttp請求客戶端使用;
我們不使用ribbon的時候,使用serviceInstance.getUri()訪問是沒問題的。
但是,當我們集成Ribbon后,就不行了。
輔助信息:
打印的信息:
服務地址:http://maq.xxxx.com:8802
服務名稱:spring-cloud-consul-producer
serviceInstance對象信息:RibbonServer{serviceId='spring-cloud-consul-producer', server=maq.xxxx.com:8802, secure=false, metadata={secure=false}}
/** * Creates a URI from the given ServiceInstance's host:port. * @param instance the ServiceInstance. * @return URI of the form (secure)?https:http + "host:port". */ public static URI getUri(ServiceInstance instance) { String scheme = (instance.isSecure()) ? "https" : "http"; //http String uri = String.format("%s://%s:%s", scheme, instance.getHost(), //host:maq.xxxx.com instance.getPort()); return URI.create(uri); }
我們訪問的:http://maq.xxxx.com:8802
主要原因:LoadBalancerClient進行手動的http請求;Ribbon集成了Apache HttpClient 、 OkHttp請求客戶端使用;
解決辦法1:
在application.properties文件中加如下配置:
ribbon.okhttp.enabled= true ribbon.restclient.enabled= true
解決辦法二:
指定訪問的http://serviceId/path (多個服務配置相同的spring.application.name=serviceId)
@RequestMapping("/getPathParam1/{user}") public String getPathParam2(@PathVariable("user") String username){ ServiceInstance serviceInstance = loadBalancerClient.choose("service-producer"); System.out.println("服務地址:" + serviceInstance.getUri()); System.out.println("服務名稱:" + serviceInstance.getServiceId()); String paramServiceResult = restTemplate.getForObject("http://" + serviceInstance.getServiceId().toString() + "/hello1/{user}", String.class,username); //String paramServiceResult = restTemplate.getForObject("http://spring-cloud-consul-producer/hello1/{user}", String.class,username); System.out.println(paramServiceResult); return paramServiceResult; }
參考鏈接:https://www.cnblogs.com/XingXiaoMeng/p/10958644.html